FreeDom

Freedom — Features & Rendering Engine

Back to README

Features

Vertical rhythm, heading scale and named grid areas (14 August 2026)

Three engine-wide corrections, each isolated in a probe measured against Firefox headless before any code changed. Structural divergence over the parity corpus fell from 154.06 to 126.04.

Also fixed on the way: ::before content is inline content and no longer takes a row of its own (it was doubling the height of Wikipedia’s reference list); multi-column fragmentation no longer reads row positions its own earlier pass had already rewritten; and a flex/grid item with both height and padding is no longer exactly its vertical padding too short.

Nested flex/grid + inline-block flow (31 July 2026)

The two structural render breaks are closed, both measured against Firefox headless:

Both are locked by pixel regression tests. See spec/page_view.md.

Still open, and now the loudest remaining gap: table auto width (shrink-to-fit) plus colspan/rowspan — every table still spans the full page and ignores spans.

Typography & inline flow parity (31 July 2026)

Four defects that made ordinary pages look broken, all measured against Firefox headless on the same HTML (firefox --headless --screenshot versus freedom --download-png):

All four are locked by pixel regression tests in tests/test_freedom.c.

(Nested flex and inline-block flow, listed as open when this section was written, are closed above.)

Inline SVG + Firefox render parity (30 July 2026)

Inline <svg> renders: shapes (rect/circle/ellipse/line/polyline/polygon), full <path> data (including elliptical arcs), <g> groups with inherited paint and composed transform, fill="currentColor" icons that take the surrounding text colour, viewBox scaling, and <text>.

It renders unconditionally — unlike <img>, which stays behind the images toggle — because the grammar the parser accepts has no URL form at all: <image>, <use>, <foreignObject>, <script> and <style> are dropped together with their subtrees, so an inline SVG structurally cannot fetch. The parser (svg_render, sv_) is pure, bounded and fuzzed (make fuzz-svg); the Cairo half (svg_paint, svp_) only draws already validated geometry. See spec/svg_render.md.

The same push closed five render gaps measured against Firefox (firefox --headless --screenshot versus freedom --download-png on the same file):

Modern Web Rendering (18 July 2026)

A modernization push across eight phases delivered a rendering engine comparable to modern browsers for trusted hosts (hosts present in both allow.conf and js.conf):

Animations & Transitions (R1): pure interpolation engine (interp module) supporting CSS easing functions (linear, ease, ease-in/out, steps, cubic-bezier), scalar and color value interpolation, keyframe interpolation, and a full animation state machine handling delays, direction, fill modes, and iteration counts. animation-duration CSS property parsed and flows through the full pipeline (CSS -> page_view -> IPC -> paint). @keyframes at-rules are parsed and stored; animation-name, animation-iteration-count, animation-direction, animation-fill-mode, animation-timing-function, and animation-delay are all parsed through the CSS cascade. In the GUI, boxes with animations automatically form stacking contexts and composite with animated opacity blended from the interpolation engine against wall-clock time.

Advanced Selectors (R2): :first-of-type, :last-of-type, :only-of-type, :nth-of-type(An+B), :nth-last-of-type(An+B), :empty, :target, and :lang(ident) pseudo-classes fully parsed and matched. The existing :not(), :is(), and :where() functional pseudo-classes were already implemented. The DOM element chain (css_chain.c) was extended with per-type sibling counting and child count for accurate matching. :empty correctly detects elements with zero child nodes. :lang() performs case-insensitive prefix matching on the lang attribute. Pseudo-elements are correctly distinguished: ::before and ::after match in the CSS cascade (for style resolution) but never match in DOM queries like querySelector (matching real browser behavior).

CSS Filters (R3): filter: blur(Npx) and filter: grayscale(N%) parsed through the full pipeline. In the GUI, boxes with filters form stacking contexts. The grayscale filter is applied via Cairo pixel manipulation: the box’s offscreen group is extracted as an image surface, each pixel is converted to grayscale (weighted luminance: 0.299R + 0.587G + 0.114B), and the modified surface is blended back with partial grayscale factor. Anti-DoS bounded at 4096px.

Layout & Positioning (R4): position: sticky implemented — boxes pin to the viewport top when scrolled past their in-flow position, common for fixed navigation bars. right and bottom CSS insets now honored for absolute/fixed positioned boxes: when right is set and left is auto, the box anchors to the right edge of its containing block (and similarly for bottom). These were already parsed but previously ignored in the box-tree position resolver.

Firefox-parity pass on modern layout (2026-07-27): the render was diffed against Firefox 140 ESR headless on the same HTML, and the gaps that broke modern pages were closed rather than guessed at.

Still v1: text does not wrap beside a lone float, align-items centers against the tallest item rather than an explicitly taller container, and width:auto is not stretched between left+right.

Out-of-flow subtree + line-box pass (2026-07-30, Stage 2d): measured against Firefox on a live Wikipedia article; four chained pipeline bugs closed.

Background Enhancements (R5): background-position parsed with keyword (left/center/right/top/bottom) and pixel value support. Applied as a Cairo translate offset in the box decoration painter, with center auto-resolving to (box_w - img_w) / 2. Multi-layer background-image with comma-separated URLs (url(a.png), url(b.png)) — second layer painted behind the first with independent sizing, repeat, and position. radial-gradient() parsed and painted via cairo_pattern_create_radial with center at box center. Gradient stop positions (e.g. red 20%, blue 80%) now consumed instead of always-even spacing.

Nested Compositor Tree (R6): stacking-context boxes now recursively compose their entire subtree as a single offscreen Cairo group. A parent with opacity properly blends its children (including nested stacking contexts) as one unit — fixing the previous limitation where child boxes with their own opacity were composited independently on top of the parent’s group. Implemented via a recursive paint_nested_children helper that traverses the box tree.

JavaScript Modernization (R7): <script defer> attribute parsed in the HTML parser and honored via two-pass script execution: sync/external scripts run first, deferred scripts run after, all sharing the same per-page JS time budget. customElements.define() now stores constructors in a live registry and fires connectedCallback during __fireDeferred. Binary arrayBuffer response type in XHR/fetch: __hostFetch returns raw binary as an ArrayBuffer, and responseType='arraybuffer' in XHR as well as fetch().arrayBuffer() return real binary data. DOM events keydown, input, change, blur, and focus were already fully wired (discovered during the audit).

Pseudo-elements (R8): ::before and ::after parsed in the selector engine and matched in the CSS cascade (rules like div::before { color: red; } apply their styles). The content property is parsed (quoted strings) and stored in css_style. DOM queries correctly reject pseudo-elements (matching browser behavior). Full content injection into the display list during the page_view walk is deferred to a follow-up.

Additional Modern Features

Current Status (July 31, 2026)