Meziantou.Framework.WebPlatform 1.0.1

Prefix Reserved
dotnet add package Meziantou.Framework.WebPlatform --version 1.0.1
                    
NuGet\Install-Package Meziantou.Framework.WebPlatform -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Meziantou.Framework.WebPlatform" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Meziantou.Framework.WebPlatform" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Meziantou.Framework.WebPlatform" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Meziantou.Framework.WebPlatform --version 1.0.1
                    
#r "nuget: Meziantou.Framework.WebPlatform, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Meziantou.Framework.WebPlatform@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Meziantou.Framework.WebPlatform&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Meziantou.Framework.WebPlatform&version=1.0.1
                    
Install as a Cake Tool

Meziantou.Framework.WebPlatform

A spec-compliant, high-performance implementation of the web platform for .NET. It parses HTML, XML, SVG, MathML and CSS exactly as a browser does, and exposes the browser DOM API (the WebIDL surface of the WHATWG and W3C specifications) with .NET naming: queries (QuerySelector, XPath, live collections), mutations, events, the CSSOM and the computed styles, forms, custom elements, accessibility, and more. A managed layout engine computes the geometry exposed by the web APIs (CSSOM View, the observers...), and the documents are painted into a display list that a rendering backend (a managed rasterizer, in a separate package) rasterizes for the screenshots and the canvases. Documents can be loaded in a browsing context that fetches their resources over the network and runs their scripts with a pluggable JavaScript engine (Meziantou.Framework.JavaScriptEngine is provided).

Every public member mapping a WebIDL member is annotated with [IdlMember(name, specUrl)]. The WebIDL names follow the .NET naming guidelines: acronyms of 3 letters or more are PascalCased and acronyms of 2 letters stay upper case (HTMLElement.innerHTML → HtmlElement.InnerHtml, toJSON → ToJson, CDATASection → CDataSection, UIEvent and HTMLBRElement → HtmlBRElement). MathML and XPath keep their casing.

Examples

Parse HTML, query the nodes and the styles

HtmlDocumentParser is in the Meziantou.Framework.WebPlatform namespace, and the DOM types (BrowsingContext, Document, HtmlAnchorElement...) are in Meziantou.Framework.WebPlatform.Dom.

var document = HtmlDocumentParser.ParseDocument("""
    <style>.important { color: red; font-weight: bold }</style>
    <ul>
      <li><a href="https://example.com/a" class="important">A</a>
      <li><a href="/b" style="color: blue">B</a>
    </ul>
    """);

// CSS selectors, with typed overloads and LINQ
var links = document.QuerySelectorAll<HtmlAnchorElement>("li > a");
var external = links.Where(a => a.Href.StartsWith("https:", StringComparison.Ordinal)).Select(a => a.TextContent);
var first = document.GetElementsByTagName("li")[0];
Assert.Equal(["A"], external);
Assert.Same(first, links[0].ParentElement);

// XPath
var result = document.Evaluate("//a[@class='important']", document, type: XPathResult.FirstOrderedNodeType);
var important = (Element?)result.SingleNodeValue;
Assert.Equal("A", important?.TextContent);

// Inline style (style attribute)
var color = links[1].Style.GetPropertyValue("color");
Assert.Equal("blue", color);

The computed styles (cascade of the style sheets, inheritance, media queries) need a browsing context, which provides the window and the viewport:

var html = """
    <style>.important { color: red; font-weight: bold }</style>
    <p class="important">Hello</p>
    """;

using var context = new BrowsingContext(new BrowsingContextOptions
{
    Viewport = new ViewportOptions { Width = 1280, Height = 720 }, // optional, 800x600 by default
});

var document = context.Navigate("https://example.com/", _ => html);
var style = context.Window.GetComputedStyle(document.QuerySelector(".important")!);
Assert.Equal("rgb(255, 0, 0)", style.Color);
Assert.Equal("700", style.GetPropertyValue("font-weight"));

See docs/dom-helpers.md, docs/selectors.md, docs/computed-style.md and docs/css-typed-om.md.

Update the DOM

The formatters are in the Meziantou.Framework.WebPlatform.Formatting namespace.

var document = HtmlDocumentParser.ParseDocument("""
    <ul>
      <li><a href="/a">A</a>
      <li><a href="/b">B</a>
    </ul>
    """);
var list = document.QuerySelector("ul")!;

// Create elements
var item = document.CreateElement<HtmlLIElement>();
var link = document.CreateElement<HtmlAnchorElement>();
link.Href = "/c";
link.TextContent = "C";
link.ClassList.Add("important");
link.SetAttribute("data-id", "3");
item.Append(link);
list.Append(item);

// Parse markup into an element, edit the styles, remove nodes
list.InsertAdjacentHtml("beforeend", "<li><a href=/d>D</a>");
link.Style.SetProperty("text-decoration", "underline");
document.QuerySelector("a[href='/b']")?.Remove();

// Serialize the document
var html = document.GetHtml();
var indented = document.ToHtml(new HtmlPrettyFormatter());
var minified = document.ToHtml(new HtmlMinifyFormatter());
Assert.StartsWith("<html><head></head><body><ul>", html, StringComparison.Ordinal);
Assert.Equal("""
    <html>
      <head></head>
      <body>
        <ul>
          <li>
            <a href="/a">A</a>
          </li>
          <li></li>
          <li>
            <a href="/c" class="important" data-id="3" style="text-decoration: underline;">C</a>
          </li>
          <li>
            <a href="/d">D</a>
          </li>
        </ul>
      </body>
    </html>
    """, indented);
Assert.Equal("""<ul><li><a href=/a>A</a><li><li><a href=/c class=important data-id=3 style="text-decoration: underline;">C</a><li><a href=/d>D</a></ul>""", minified);

Element.SetHtml() and Document.ParseHtml() insert untrusted markup with the HTML Sanitizer API. See docs/html-formatting.md and docs/css-formatting.md for the serialization options.

Allow network requests

Nothing is fetched unless a DocumentLoader is configured. With a loader, the browsing context loads the documents of the navigations and the iframe elements, the style sheets (<link rel=stylesheet>, @import), the images and, when a script engine is configured, the scripts:

using var context = new BrowsingContext(new BrowsingContextOptions
{
    DocumentLoader = DocumentLoader.Create(),  // HTTP GET requests with a shared HttpClient (or pass your own)
    CookieJar = new CookieJar(),               // optional: the cookies (RFC 6265bis, document.cookie, cookieStore)
});

context.Navigate("https://example.com/");
await context.EventLoop.RunUntilIdleAsync(); // runs the tasks until the document and its resources are loaded

var document = context.Document;

DocumentLoader.Create() requests any URL. A custom loader can filter the requests (to prevent server-side request forgery with untrusted documents), serve them from a cache or from the disk:

internal sealed class SameHostLoader(string host) : DocumentLoader
{
    private static readonly DocumentLoader Http = DocumentLoader.Create();

    public override ValueTask<DocumentResource?> LoadAsync(DocumentRequest request, CancellationToken cancellationToken)
    {
        if (new Uri(request.Url).Host != host)
            return ValueTask.FromResult<DocumentResource?>(null); // network error

        return Http.LoadAsync(request, cancellationToken);
    }
}

See docs/browsing-context.md.

Execute scripts

Scripts only run when a JavaScript engine is plugged into the browsing context. The Meziantou.Framework.WebPlatform.JavaScript package provides one, based on Meziantou.Framework.JavaScriptEngine, in the Meziantou.Framework.WebPlatform.JavaScript namespace:

using var engine = new JavaScriptScriptEngine(new JavaScriptScriptEngineOptions
{
    Timeout = TimeSpan.FromSeconds(5), // per script or callback
});

using var context = new BrowsingContext(new BrowsingContextOptions
{
    ScriptEngine = engine,
    DocumentLoader = DocumentLoader.Create(), // optional: external scripts, modules, fetch, XMLHttpRequest, WebSocket, EventSource...
    UnhandledScriptError = (window, error) => Console.Error.WriteLine(error),
    ConsoleMessage = (window, message) => Console.WriteLine(message.Text), // console.log(), console.count()...
});

var document = await context.NavigateAsync("https://example.com/", _ => """
    <title>Example</title>
    <ul id=list></ul>
    <script>
      setTimeout(() => document.getElementById('list').innerHTML = '<li>a<li>b', 100);
    </script>
    """);

// Run the tasks and the timers until there is nothing left
do { await context.EventLoop.RunUntilIdleAsync(); } while (await context.EventLoop.WaitForNextTimerAsync());

Assert.Equal("<li>a</li><li>b</li>", document.GetElementById("list")!.InnerHtml);

// Evaluate code in the realm of a window
var title = engine.Evaluate(context.Window, "document.title");
Assert.Equal("Example", title.AsString());

The scripts run in the process: read the threat model in docs/scripting.md before running untrusted documents.

Take screenshots

The documents are painted by the library into a backend-agnostic display list; the Meziantou.Framework.WebPlatform.Imaging package draws them, and decodes and encodes the images, with Meziantou.Framework.Imaging, a fully managed library (no native dependency: the same pixels on every platform). ImagingRenderingBackend and the screenshot methods are in the Meziantou.Framework.WebPlatform.Imaging namespace:

using var context = new BrowsingContext(new BrowsingContextOptions
{
    Viewport = new ViewportOptions { Width = 1280, Height = 720, DevicePixelRatio = 2 },
    DocumentLoader = DocumentLoader.Create(),
    RenderingBackend = new ImagingRenderingBackend(),
});

context.Navigate("https://example.com/");
await context.EventLoop.RunUntilIdleAsync();

await File.WriteAllBytesAsync("page.png", context.TakeScreenshotAsPng());            // the viewport: 2560x1440 pixels
using var title = context.Document.QuerySelector("h1")!.TakeScreenshot();           // an element, as an Image<Rgba32>

// Print the document: the print media type, the @page rules, one image per page
var pages = context.RenderPagesAsPng(new PrintOptions { PageWidth = 794, PageHeight = 1123 }); // A4 at 96 dpi

See docs/rendering.md for what is painted, and Printing for the pages.

Limitations

  • Layout. The layout engine is internal (docs/layout.md): it runs on demand, when a web API reads the geometry, and it is exposed only through the web APIs: CSSOM View (getBoundingClientRect(), getClientRects(), the offset*, scroll* and client* members, elementFromPoint() and the hit testing, caretPositionFromPoint(), getBoxQuads(), the MouseEvent coordinates, the scrolling and its events), the used values of getComputedStyle() (see docs/computed-style.md), the SVG geometry, ResizeObserver, IntersectionObserver and the lazy loading, the layout shifts, the size and scroll-state container queries, the viewport units and window.visualViewport, Selection.modify() and the caret movement keys. It implements the block and inline layouts (line breaking, bidirectional text, the CSS Text features), the floats and shape-outside, the replaced elements and the form controls, the intrinsic sizes, the containment and content-visibility, the positioned layout and the anchor positioning, the overflow (and text-overflow, line-clamp), the scrolling, the scroll snapping and the scroll anchoring, the scroll markers and the scroll buttons (::scroll-marker-group, ::scroll-marker, ::scroll-button(), scroll-target-group), the flex (and -webkit-box), grid (with the subgrids), grid lanes (masonry) and table layouts, the ruby layout, the box alignment, the gap decorations (the column and row rules of the grid, flex and multi-column containers), the writing modes, the multi-column layout and the block fragmentation in its columns (with the floats pushed to the next column and the repeated table headers and footers), the paged media (the pagination of the printed documents: @page, the page breaks, the named pages, the page-margin boxes), the MathML Core layout and the SVG layout. The wheel, a panning touch, the keys and the scrollbars scroll (BrowsingContext.Input). Not implemented: the selection with the pointer, the layout of the pages whose inline size differs from the first page, the repetition of a hyphen at the start of the next line, the spelling changes at a hyphenation break of the languages other than Dutch, Hungarian and Pinyin and the hyphenation dictionaries under copyleft licenses (cs, hu, hy, lv), the scrolling of a ::scroll-marker-group that is a scroll container, pinch zoom, and, in the shaping of the complex scripts (the shaper of Meziantou.Framework.Fonts), the Myanmar Zawgyi encoding and the Arabic fallback shaping of the Windows-1256 fonts.
  • No rasterizer in the core library. The documents are painted into a backend-agnostic display list (the painting order of CSS, the stacking contexts, the clips, the transforms and effects, the backgrounds, the borders, the outlines, the texts with the glyphs of the managed text shaping, the images including the SVG images, the SVG content): the pixels are produced by a rendering backend plugged with BrowsingContextOptions.RenderingBackend: ImagingRenderingBackend of the Meziantou.Framework.WebPlatform.Imaging package (the managed drawing API of Meziantou.Framework.Imaging), which also takes the screenshots (see docs/rendering.md) and draws the 2D canvases (CanvasRenderingContext2D, OffscreenCanvas, also in the workers) and the paint() images of the paint worklets (CSS.paintWorklet, see docs/rendering.md). Without a backend, nothing is rasterized and canvas.getContext('2d') returns null. Not painted yet: the color glyphs other than the layers of COLR version 0 with the palettes of font-palette (the paint graphs of COLR version 1, the bitmap and SVG glyphs), the wrapping of the SVG texts in the shapes of shape-inside. The canvas layers (beginLayer()) and the float16 canvases are not implemented. As in Blink, the painted boxes and the baselines are snapped to the device pixels and the metrics of the fonts are rounded to whole pixels (the layout keeps its fractional geometry).
  • Injected user input. There is no window: the host injects the pointer and wheel input of the user with BrowsingContext.Input (mouse, pen and touch pointers, wheel; see docs/browsing-context.md), which fires the trusted pointer, mouse, touch and click events and runs the default actions (focus, activation, light dismiss, drag and drop, scrolling, the picker of the select elements: the customizable select, appearance: base-select, is rendered) and the classic scrollbars (a press on the track, a drag of the thumb). The keyboard events are dispatched by the host. There is no pinch zoom.
  • Opt-in network and scripting. Without a DocumentLoader, nothing is fetched; without a script engine, the scripts are never fetched nor run, and the event handler attributes have no effect. A document parsed with HtmlDocumentParser has no browsing context: no window, no computed style, no event loop (the mutation observer callbacks are not invoked).
  • Images are decoded by the rendering backend, not by the core library: without a backend, only the natural dimensions of the images are read from their header (decode() resolves once the image is available, createImageBitmap() rejects the images and the blobs). The Imaging backend decodes PNG (including the animated PNG), JPEG (including CMYK), GIF, WebP, AVIF, BMP and ICO images, with their EXIF orientation, their EXIF resolution (the density-corrected size) and their color profile.
  • Media (audio, video) are not decoded by the library: the processing model of the media elements (resource selection, events, play(), seeking...) runs on top of a media backend provided by the application (BrowsingContextOptions.MediaBackend, see docs/browsing-context.md); without it, the media elements have no media resource. The Media Source Extensions are implemented on top of the segment parsers of the backend (the coded frames are not decoded); Encrypted Media and the controls of the media elements are not implemented.
  • No downloads, and the third-party cookies are not blocked.
  • Content Security Policy covers the fetch directives, the inline checks (scripts, styles, event handlers, style attributes, javascript: URLs), 'unsafe-eval'/'wasm-unsafe-eval' (eval() and the Function constructors), the navigation and document directives (frame-src, form-action, frame-ancestors, base-uri, object-src, worker-src), upgrade-insecure-requests, the inheritance of the policies and the Trusted Types directives, with their violation reports (securitypolicyviolation, report-uri, and report-to with the Reporting API): no CSP Embedded Enforcement (the csp attribute of the iframe element). The Reporting API only generates the CSP, COEP and test reports (no deprecation, intervention, COOP or Document Policy reports).
  • Streams cannot be transferred, and the tentative URLPattern methods compareComponent() and generate() are not implemented.
  • Experimental APIs. The public APIs of the tentative features (proposals that no specification defines yet, e.g. Element.StreamAppendHtml(), Element.MatchContainer()) have the [Experimental] attribute: suppress their diagnostic (WEBPLATEXP0002...) to use them, see docs/experimental-apis.md.

Specifications

Area Specification Status
Encoding WHATWG Encoding Done
URL WHATWG URL, UTS #46 Done
URL Pattern URL Pattern Done (UrlPattern; the patterns are compiled to .NET regular expressions with the semantics of the ECMAScript v flag, the Unicode property escapes of the custom groups are limited to the General_Category values; the tentative compareComponent() and generate() are not implemented)
HTML parsing WHATWG HTML Done (the encoding declared by a <meta> element is found by tokenizing the head, as the browsers do and as proposed by whatwg/html#6962, rather than by the prescan of the first 1024 bytes; a <meta> element of the head after the first 1024 bytes changes the encoding when the parser inserts it, without the re-parse of the specification; the encoding of a document that does not declare it is detected from its content by a port of chardetng, the detector of Firefox, see Encoding detection)
HTML serialization WHATWG HTML Done (innerHTML, outerHTML, getHTML(); Document.GetHtml() and Document.WriteHtml(TextWriter) serialize a whole document)
HTML formatting WHATWG HTML Done (Node.ToHtml(HtmlFormatter): minified output, pretty printing and custom formatters): see docs/html-formatting.md
CSS formatting CSSOM Done (CssStyleSheet.ToCss(CssFormatter), CssRule.ToCss, CssStyleDeclaration.ToCss: minified output, pretty printing and custom formatters): see docs/css-formatting.md
DOM WHATWG DOM Done (LINQ helpers: tree walks, typed queries, CreateElement<T>()): see docs/dom-helpers.md
Selectors Selectors Level 4, CSS Syntax Done (read-only selector object model: SelectorList.Parse, CssStyleRule.Selectors, specificity, matching with a parsed selector): see docs/selectors.md
XML, DOMParser, XMLSerializer HTML XML syntax, DOM Parsing Done
DOM XPath DOM over System.Xml.XPath Done
HTML element interfaces, reflection WHATWG HTML Done
SVG and MathML element interfaces SVG 2, SVG Paths, Filter Effects, Geometry, MathML Core Done (path data API: getPathData, setPathData; the length of the paths is computed from the d property, which maps the d attribute; getBBox(), the text layout, the transforms and the hit testing are computed from the geometry: see docs/layout.md and docs/computed-style.md)
Forms WHATWG HTML, XHR FormData Done (the submission navigates the target browsing context, with the DocumentLoader for the network requests; no user interaction states)
CSS syntax, CSSOM CSS Syntax, CSSOM, CSS Values, CSS Color Done (the style sheets of <link rel=stylesheet>, of the @import rules and of the xml-stylesheet processing instructions are fetched by the DocumentLoader)
CSS Typed OM CSS Typed OM Done (attributeStyleMap, styleMap, computedStyleMap(), the numeric, keyword, unparsed, transform, image and color values; the colors of the properties are not reified, like in the browsers): see docs/css-typed-om.md
CSS Parser API CSS Parser API (WICG draft) Done on the parser of CSS Syntax (CSS.parseStylesheet(), parseRule(), parseDeclaration(), parseValue()..., the CSSParser* objects; the draft's inconsistent types follow CSS Syntax; can be hidden from the scripts): see docs/css-parser-api.md
Cascade, computed style CSS Cascade, Media Queries, CSSOM, CSS Mixins (custom functions), CSS Color Adjustment (color schemes, forced colors mode) Done (getComputedStyle with the layout-dependent resolved values from the layout, innerText; the :visited links with a history provided by the application, painted only): see docs/computed-style.md
Layout, CSSOM View CSS 2, CSS Display, CSS Flexbox, CSS Grid, CSS Grid 3 (grid lanes), CSS Gap Decorations, CSS Tables, CSS Ruby, CSS Text, CSS Writing Modes, CSS Paged Media, CSS Anchor Positioning, CSSOM View, Resize Observer, Intersection Observer Done (internal layout engine exposed through the web APIs, the user input and the printing): see docs/layout.md
Rendering CSS Backgrounds, Filter Effects, CSS Masking, SVG 2, HTML canvas, Paint Timing Opt-in (a backend-agnostic display list rasterized by the Meziantou.Framework.WebPlatform.Imaging package: screenshots, 2D canvases, image decoding): see docs/rendering.md
Animations Web Animations, CSS Animations, CSS Transitions Done (Element.animate(), getAnimations(), the CSS animations and transitions in the computed styles, their events; the animations follow the clock of the event loop; the scroll and view timelines of Scroll-driven Animations follow the scroll positions; no animation triggers), and the SVG animations (SMIL: animate, set, animateMotion, animateTransform, the timing model, animVal, the timing events): see docs/animations.md
View transitions CSS View Transitions 1, 2 Done for the transitions of a document (document.startViewTransition(), ViewTransition, the ::view-transition-*() pseudo-element tree with its user agent style sheet and animations, the snapshots rasterized by the rendering backend, the transition types, view-transition-class, the nested groups), for the scoped transitions (element.startViewTransition(), element.activeViewTransition, view-transition-scope, the pseudo-element tree painted above the contents of its root element, the rendering paused within it) and for the cross-document transitions (@view-transition, pageswap, pagereveal, revealed once the document is not render-blocked): see docs/view-transitions.md
Compatibility WHATWG Compatibility Done (the -webkit- prefixed properties, keywords, gradients, at-rules and media features; -webkit-gradient(); the legacy -webkit-box is laid out as a flex container; window.orientation is not exposed, as in the desktop browsers)
Accessibility WAI-ARIA, HTML-AAM, Accessible Name Done (Element.ComputedRole, Element.ComputedName): see docs/accessibility.md
Media elements WHATWG HTML Done on top of a media backend provided by the application (audio, video, source, resource selection, events, playback state, TimeRanges, audio and video tracks, media documents, and the Media Source Extensions: MediaSource, SourceBuffer, ManagedMediaSource, in the windows and the dedicated workers): see docs/browsing-context.md. Not done: the controls
Text tracks and WebVTT WHATWG HTML, WebVTT Done (track, TextTrack, VTTCue, VTTRegion, the WebVTT parsers, the cue events, the rendering of the cues over the videos, ::cue, ::cue(), ::cue-region, :past, :future): see docs/browsing-context.md. Not done: the user preferences for the track selection, the animation of the scrolling regions
HTML Sanitizer API WHATWG HTML Done (setHTML, parseHTML, Sanitizer)
HTML insertion methods, partial updates WHATWG HTML (<template for>, HTML insertion methods), proposal whatwg/html#12758 Done (appendHTML(), beforeHTML()... and the streaming methods streamAppendHTMLUnsafe()..., the tentative buffer, sanitize and src attributes of <template for>; no in-place <template for="">): see docs/partial-updates.md
Trusted Types Trusted Types Done (enforcement is opt-in): see docs/trusted-types.md
Selection API Selection API Done (modify() moves the selection over the layout; the selection also changes with the caret movement keys of the editable content, not with the pointer; toString() returns the rendered text of the range)
Custom elements WHATWG HTML (CustomElementRegistry, ElementInternals, form-associated custom elements, :state()) Done (the elements are defined with .NET constructors): see docs/custom-elements.md
Popover API, invoker commands WHATWG HTML Done (focus, light dismiss and close requests are processed for the events dispatched by the library or the scripts: there is no user input)
Text directives URL Fragment Text Directives Done (#:~:text=, ::target-text, document.fragmentDirective, the user activation and cross-origin restrictions, force-load-at-top; the collation of the locale is not used): see docs/browsing-context.md
Fullscreen API Fullscreen Done (requestFullscreen(), exitFullscreen(), fullscreenElement, the events of the rendering update, :fullscreen, the top layer and ::backdrop, the fullscreen permissions policy feature, the keyboard lock of the Escape key; nothing is displayed: the host resizes the viewport with BrowsingContextOptions.EnterFullscreen): see docs/browsing-context.md
Pointer Lock API Pointer Lock Done (requestPointerLock(), exitPointerLock(), pointerLockElement, pointerlockchange and pointerlockerror, movementX and movementY, the events of the locked mouse; the host locks its pointer with BrowsingContextOptions.RequestPointerLock): see docs/browsing-context.md
Web Locks Web Locks API Done (navigator.locks in the windows and the workers, request() with the modes, ifAvailable, steal and signal, query(), the lock managers per storage key of a browsing context group, partitioned for the third-party contexts, the release when a document or a worker is discarded): see docs/browsing-context.md
Deferred fetching Fetch Done (fetchLater() and FetchLaterResult: the requests are sent when the document is destroyed or after activateAfter, the quota shared by the documents of an origin and delegated to the cross-origin frames by the deferred-fetch and deferred-fetch-minimal policy-controlled features; no back/forward cache): see docs/browsing-context.md
Storage manager Storage Done (navigator.storage in the windows and the workers: estimate() from the usage that the storage backends report, persisted(), persist() answered by the host; no storage buckets): see docs/browsing-context.md
Origin private file system File System Done (getDirectory(), the file and directory handles, the async iteration, FileSystemWritableFileStream, FileSystemSyncAccessHandle in the dedicated workers, the locks, the serialization of the handles, move() and remove(), on a delegated FileSystemBackend; no FileSystemObserver): see docs/browsing-context.md
Prioritized Task Scheduling Prioritized Task Scheduling Done (scheduler.postTask(), scheduler.yield(), TaskController, TaskSignal, TaskSignal.any(), the priorities in the event loop, in the windows and the workers; the scheduling state is not propagated by the await of a promise that another task settles: it is not attached to the promise jobs yet): see docs/browsing-context.md
Close watchers WHATWG HTML Done (CloseWatcher, the close watcher manager shared with the dialogs, the popovers and the pickers of the select elements; the close request is the Escape key): see docs/browsing-context.md
Editing, drag and drop WHATWG HTML, execCommand, Drag and drop Partial (editing hosts, designMode, the delete, forwardDelete, insertText and selectAll commands, hidden=until-found; DataTransfer and the drag-and-drop processing model, driven by the host with DragAndDropOperation): see docs/browsing-context.md
Browsing contexts WHATWG HTML (Window, iframe, Location, History) Opt-in (nested documents, navigations, window.open(), focus; the resources are fetched only with a DocumentLoader): see docs/browsing-context.md
Client Hints Client Hints Infrastructure, User-Agent Client Hints Done (the Accept-CH cache, the Sec-CH-* request headers with the values of BrowsingContextOptions.ClientHints and of the viewport, their delegation with the permissions policy and <meta http-equiv="delegate-ch">, the Critical-CH restarts and navigator.userAgentData; the requests of the workers have no hint, and of Clear-Site-Data only the clearing of the hints is implemented): see docs/browsing-context.md
Scripting WHATWG HTML (script elements, event handlers, javascript: URLs, timers, error reporting) Opt-in: a JavaScript engine is plugged into the browsing contexts (Meziantou.Framework.WebPlatform.JavaScript for Meziantou.Framework.JavaScriptEngine), with module scripts and import maps: see docs/scripting.md
Speculation rules WHATWG HTML, Prefetch, Prerendering Done (<script type="speculationrules"> and the Speculation-Rules header, list and document rules, eagerness with the pointer of the user, navigational prefetches used by the navigations, prerendering traversables activated by the navigations, document.prerendering, prerenderingchange, activationStart: see docs/browsing-context.md); the workers and the media elements of a prerendering document are not suspended, and there is no HTTP cache
Worklets, CSS Painting API, CSS Layout API, Animation Worklet WHATWG HTML, CSS Painting API, CSS Layout API, CSS Animation Worklet API Done with a script engine that supports the module scripts (Worklet.addModule(); CSS.paintWorklet, registerPaint(), PaintRenderingContext2D and the paint() images, which need a rendering backend; CSS.layoutWorklet, registerLayout() and the display: layout() boxes, without fragmentation by the layout; CSS.animationWorklet, registerAnimator() and WorkletAnimation: see docs/scripting.md, docs/rendering.md, docs/layout.md and docs/animations.md); the global scopes of a worklet are realms of the script engine of the document. The audio worklets are not implemented
Web Cryptography Web Cryptography API, Secure Curves, Modern Algorithms Done (implemented in JavaScript in the WebIDL bindings, with managed primitives; no SLH-DSA): see docs/scripting.md
WebAssembly WebAssembly JavaScript Interface, Web API Opt-in: a WebAssembly runtime is plugged into the browsing contexts (Meziantou.Framework.WebPlatform.Wasmtime for Wasmtime, WebAssembly 3.0 without the threads): see docs/scripting.md
Streams WHATWG Streams, TextEncoderStream, TextDecoderStream, Blob.stream(), WHATWG Compression (CompressionStream, DecompressionStream) Done (implemented in JavaScript in the WebIDL bindings; streams cannot be transferred): see docs/scripting.md

Building

./eng/webplatform/fetch-tests.sh
dotnet test --project tests/Meziantou.Framework.WebPlatform.Tests
dotnet test --project tests/Meziantou.Framework.WebPlatform.Imaging.Tests
dotnet test --project tests/Meziantou.Framework.WebPlatform.Wpt

The web-platform-tests (testharness.js tests and reftests, the reftests being rendered by the Imaging backend) run with the script engine of Meziantou.Framework.WebPlatform.JavaScript: see docs/web-platform-tests.md.

See docs/updating-specs.md to update the specification data, docs/fuzzing.md to fuzz the parsers, and docs/performance.md for the benchmarks.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed.  net11.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (6)

Showing the top 5 NuGet packages that depend on Meziantou.Framework.WebPlatform:

Package Downloads
Meziantou.Framework.HtmlSanitizer

Provide helpers to sanitize HTML fragment

Meziantou.Framework.HtmlToMarkdown

Convert HTML fragments to Markdown

Meziantou.Framework.WebPlatform.Imaging

Rasterizes the documents of Meziantou.Framework.WebPlatform with the fully managed drawing API of Meziantou.Framework.Imaging (a RenderingBackend): screenshots of the pages and of the elements, 2D canvases, image decoding and encoding.

Meziantou.Framework.HumanReadableSerializer.Html

Formats the HTML values (text/html) serialized by Meziantou.Framework.HumanReadableSerializer, using the spec-compliant HTML parser of Meziantou.Framework.WebPlatform

Meziantou.Framework.WebPlatform.Wasmtime

Runs the WebAssembly modules of the scripts of Meziantou.Framework.WebPlatform with Wasmtime (a WebAssemblyRuntime for the WebAssembly JavaScript API).

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 9 10/21/2026
1.0.0 99 10/18/2026