Prototypes GalleyP30 · Layout engine

Galley against Chromium

Every document below is drawn twice: by Galley on a canvas and by this browser in a frame, with the same fonts. Then every element’s box and every line of text is compared. A document passes when nothing is more than half a pixel from where Chromium puts it. The fuzzer writes new documents from a seed, with blocks, inline text, floats, flex and grid, and checks them the same way.

Measuring…

DocumentBoxesLinesFurthestGalleyResult

The fuzzer

Each seed writes one document. The first one that does not match opens in the engine.

    How Galley is built
    1. Galley is a layout engine written for this prototype, in plain JavaScript with no dependencies. It reads HTML and CSS, works out where every box and every line of text goes, and draws the page on a canvas. The browser is used for two things only: the canvas, and the width of a run of text from its text shaper, which reads the same font files.
    2. The HTML parser repairs a document the way a browser does: it adds the html, head and body, closes a paragraph before a block, a list item before the next one, and an element left open when its parent ends. The CSS parser follows CSS Syntax Level 3, with @media, custom properties, calc(), min(), max() and clamp(), and colors up to oklch().
    3. Selectors match from right to left, with :is(), :not(), :where(), :nth-child() and the four combinators, and the cascade sorts by origin, importance, specificity and order. Galley carries Chromium’s own default stylesheet for the elements a document of text and boxes uses.
    4. Galley lays a page out by CSS 2.1 and the CSS modules after it: margins that collapse through parents and empty blocks, floats placed as far up as they fit, clearance, new formatting contexts that keep beside floats, inline boxes split across lines, inline-blocks on their baselines, vertical-align, lists and counters, tables with spans and separated or collapsed borders, flexbox with its freeze loop for grow and shrink, grid with fr, minmax(), repeat(auto-fill) and named areas, and absolute, fixed and relative positioning.
    5. Text is broken into lines at the places Unicode allows: after spaces, hyphens and dashes, between ideographs, and inside a word with overflow-wrap: anywhere or break-word. Each line box is as tall as the boxes on it, with each font’s ascent and descent from the font file and the half-leading rounded the way Chromium rounds it.
    6. Galley has one thing a browser does not: with Galley’s typesetting on, it hyphenates English with Liang’s algorithm and the TeX patterns, and breaks each paragraph with Knuth and Plass’s algorithm, which chooses the breaks for the whole paragraph that keep the spaces most even.
    7. The page is drawn from a display list in CSS’s painting order: stacking contexts, backgrounds, borders with rounded corners, shadows, gradients, text with its decorations, opacity and clipping. The same list is written as an SVG file by the export.
    8. Every document is drawn by Chromium too, in a frame beside the canvas, and every element’s box and every line of text is compared. The page against Chromium does this for the whole corpus, and a fuzzer writes new documents from a seed and checks them the same way.