Version 3 retains the application integration model around Container, Document,
and ViewportContainer. Geometry and measurements use float. This is a source
migration, not binary compatibility with version 2.
Code shared by desktop platforms can hold a Container and use:
Render(html),Document, andAnchorClicked.ShouldCreateElementCallbackandCreateElementCallback.ImportCssRequest, returning both CSS and its base URL for relative resources.- Writable
DefaultFontName,DefaultFontSize, and floating-pointScaleFactor.
Platform containers inherit these hooks. There is one creation delegate, rather
than separate Avalonia/WPF/Cocoa delegates. Attached controls handle Render(html)
and schedule layout and painting. Without an attached control it loads the document;
call Document.Render(width) to calculate layout. Use the UI thread for attached hosts.
Container container = platformContainer;
container.ShouldCreateElementCallback = tag => tag == "widget";
container.CreateElementCallback = (
string tag, IReadOnlyDictionary<string, string> attributes, out SizeF size) =>
{
// Resolve and measure the application's control here.
size = new SizeF(80.5f, 24.25f);
return 42;
};
container.Document.ViewElementsNeedLayout += () =>
{
if (container.Document.GetElementInfo(42) is { } info)
{
// Position the application control using info.PosX/PosY/Width/Height.
// These are document coordinates; apply host scrolling/scaling as needed.
}
};
container.Render("<widget data-control-ident='example'></widget>");Custom IDs must be positive and unique within a load; zero declines replacement.
Attributes are a case-insensitive dictionary, preserving values containing newlines
or equals signs. Creation returns the measured SizeF separately from its ID.
The callback must not re-enter the document.
GetElementInfo(id) returns a nullable immutable snapshot with Id, Bounds,
PosX, PosY, Width, and Height. Null means absent or without visible layout.
It replaces the preview's GetCustomElementBox; there is no parallel legacy API.
The snapshot owns no native handle and remains a snapshot after HTML replacement.
Attributes come from the creation callback, not a serialized string on the layout
result. The old ElementInfo.Text field is not part of this layout API.
DocumentSizeKnown, SetViewport, and SetMasterCSS remain available. Changing
master CSS affects the next HTML load. Applications can continue switching a body
class and reloading HTML for theme changes. Desktop controls drive animations
without an application timer.
Avalonia and WPF controls accept ownsContainer (default true, preserving their
existing disposal behavior). Pass false when the application owns a supplied
container; disposing the control then detaches its subscriptions and timer while
leaving the container usable. The application must eventually dispose that container.
An Avalonia control that creates its own container always owns it.
Use createInteractiveElements: false (Avalonia) or createOldStyleControls: false
(WPF) when the application supplies custom-element callbacks. Disposal preserves
those application callbacks. A replacement control must reconnect the application's
child controls; built-in child controls are removed on disposal and require an HTML
reload to recreate. Attach only one host control to a container at a time.
- Native handles and callback tables are owned by the wrapper, not the application.
Document.Drawrecords an immutable display list; platform replay performs drawing.- Renderer hooks retain structured gradients, transforms, and group opacity rather than returning to the old background-only drawing contract.
LibInterop.GetDiagnostics()andDocument.GetDiagnostics()return immutable lifecycle snapshots. The obsoleteDocumentRefCountis removed; useNativeDocumentCountto monitor owned bridge handles. See the diagnostics section below.- Viewport values, font metrics, custom sizes, and layout results use floats. Convert platform doubles at the boundary rather than rounding to integer pixels.
No litehtml engine or native ABI changes are required for this managed API revision.
LibInterop.GetDiagnostics() aggregates currently live containers in this loaded
assembly. container.Document.GetDiagnostics() reports one container and returns
zero counters after disposal. Both can be read without invoking native code.
| Counter | Meaning |
|---|---|
TotalContainerCount |
Containers with an owned native bridge handle |
NativeDocumentCount |
Owned native bridge handles (currently one per container, including before HTML is loaded) |
HasDocument |
Containers with a successfully loaded HTML document; 0 or 1 for a document snapshot |
CustomElementCount |
Distinct positive custom-element IDs registered by the current successful load, including hidden elements |
ParseCount |
Successful HTML loads since creation, summed across currently live containers for the global snapshot |
A successful replacement replaces the custom-element count and increments parses. A failed native load retains the previous snapshot. A captured managed callback exception can be reported after the native load succeeds; counters reflect the native load's result. Disposal or finalization removes a container's contribution, including its parse history. Render, draw, scroll, and animation pulses do not increment parse counts.
These counters measure wrapper ownership and registrations, not every internal
engine allocation. They help identify accumulating containers and registrations;
they cannot prove the absence of native memory leaks. For the old debug display,
replace DocumentRefCount with NativeDocumentCount and a corresponding label;
the latter counts owned bridge handles, not C++ shared-pointer references. The diagnostics registry holds no container references.
Use Container.Render(html) to replace HTML in an attached desktop control. The
controls' load handlers are implementation details; examples use this common entry
point. Custom container subclasses can override protected OnRenderHtml to supply
host scheduling. The default implementation calls Document.Load.
For a custom host, the distinct low-level steps remain explicit:
Document.Load(html, userCss)parses HTML without scheduling a UI update.Document.Render(width)calculates layout at the current animation time.Document.RenderFrame(...)advances time, calculates layout, and returns scheduling information in one operation. It replaces the separateNextAnimationDelayquery.Document.SetTime(...)remains useful for synchronizing the clock before hover or other input, independently of layout.AnimationDriverdoes this for desktop hosts.Document.Draw(...)records drawing commands;ViewportContainer.Draw()also replays them with the viewport's offset. These are distinct host responsibilities.
CreateFromString was an alias for Load and is removed. Mouse movement uses
OnMouseOver with overloads for document coordinates alone or separate document and
client coordinates; the differently named OnMouseMove alias is removed. Text drawing
has one virtual method with optional decorationOpacity, rather than two override paths.
Applications configure custom elements and CSS through callback properties. The
ShouldCreateElement, CreateElement, and ImportCss methods are protected subclass
hooks (also accessible internally to the bridge), not alternative public entry points.
There is no public HTML-dispatch event between a container and its control.