Engineer Notes
Web Conformance Test Plan — APHTML Layout Engine
This document defines the conformance test matrix for the APHTML layout engine. Each test case maps to a W3C CSS specification section and is prioritized as P0 (must pass for release), P1 (should pass for release), or P2 (deferred / aspirational).
Web Conformance Test Plan — APHTML Layout Engine
This document defines the conformance test matrix for the APHTML layout engine. Each test case maps to a W3C CSS specification section and is prioritized as P0 (must pass for release), P1 (should pass for release), or P2 (deferred / aspirational).
Tests are structured by formatting context. Each test specifies an HTML/CSS input and the expected LayoutBox output (position, size, margins, padding, border) that Manniquin should validate against a Chrome reference render.
1 Flexbox (CSS Flexible Box Layout Level 1)
All flexbox tests validate that FlexFormattingContext → IFlexLayoutProvider → YogaFlexLayoutProvider produces spec-conformant results.
1.1 Container Properties
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| F-001 | P0 | §9.1 | flex-direction: row lays children left-to-right | 3 children 100px wide in 400px container | x: 0, 100, 200 |
| F-002 | P0 | §9.1 | flex-direction: column lays children top-to-bottom | 3 children 50px tall | y: 0, 50, 100 |
| F-003 | P0 | §9.1 | flex-direction: row-reverse reverses order | 3 children | First child at right edge |
| F-004 | P0 | §9.1 | flex-direction: column-reverse reverses order | 3 children | First child at bottom |
| F-005 | P0 | §9.2 | flex-wrap: wrap wraps children to next line | 5 × 100px children in 300px container | 3 on line 1, 2 on line 2 |
| F-006 | P0 | §9.2 | flex-wrap: wrap-reverse wraps upward | Same as F-005 | Line 2 above line 1 |
| F-007 | P0 | §9.2 | flex-wrap: nowrap shrinks children | 5 × 100px children in 300px container | All on one line, each ≤ 60px |
1.2 Item Properties
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| F-010 | P0 | §9.7 | flex-grow distributes extra space | 2 items, grow 1 & 2 in 300px | 100px & 200px |
| F-011 | P0 | §9.7 | flex-shrink reduces oversized items | 2 × 200px items, shrink 1 & 3 in 300px | 150px & 50px proportionally |
| F-012 | P0 | §9.8 | flex-basis: 0 uses content as base | Item with text, basis 0 | Width = grown share, not content |
| F-013 | P0 | §9.8 | flex-basis: auto uses item width | Item with width 150px, basis auto | Starts at 150px before grow/shrink |
| F-014 | P1 | §9.8 | flex-basis percentage resolves to container | flex-basis: 50% in 400px container | Base = 200px |
| F-015 | P1 | §9.5 | order changes visual order | 3 items with order 3, 1, 2 | Visual: item2, item3, item1 |
1.3 Alignment
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| F-020 | P0 | §9.3 | justify-content: center | 200px of items in 400px | Centered, 100px start offset |
| F-021 | P0 | §9.3 | justify-content: space-between | 3 items in 300px | 0, 100, 200 (no gaps at edges) |
| F-022 | P0 | §9.3 | justify-content: space-around | 3 items | Equal half-gaps at edges |
| F-023 | P0 | §9.3 | justify-content: space-evenly | 3 items | Equal gaps including edges |
| F-024 | P0 | §9.4 | align-items: center | Items of varying height | All vertically centered in line |
| F-025 | P0 | §9.4 | align-items: stretch (default) | Items without explicit height | All stretch to line height |
| F-026 | P0 | §9.4 | align-items: flex-start / flex-end / baseline | Mixed height items | Correct alignment per value |
| F-027 | P1 | §9.4 | align-self overrides align-items per item | One item with align-self: flex-end | That item at end, others at start |
| F-028 | P1 | §9.4 | align-content: center (multi-line) | Wrapped flex, align-content center | Lines centered in cross axis |
1.4 Gaps
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| F-030 | P0 | CSS Box Alignment §8 | gap: 10px between items | 3 × 80px items in 300px, gap 10px | x: 0, 90, 180 |
| F-031 | P1 | CSS Box Alignment §8 | row-gap + column-gap differ | Wrapped flex, row-gap 5px, col-gap 20px | Proper spacing per axis |
| F-032 | P1 | CSS Box Alignment §8 | Percentage gap | column-gap: 10% in 200px container | 20px gaps |
1.5 Auto Margins in Flex
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| F-040 | P1 | §8.1 | margin-left: auto pushes item right | Single item in 300px row flex | Item at right edge |
| F-041 | P1 | §8.1 | Opposing auto margins center item | margin: 0 auto on one item | Item horizontally centered |
2 CSS Grid (CSS Grid Layout Level 1)
2.1 Track Definition
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| G-001 | P0 | §7.2 | grid-template-columns: 100px 200px fixed tracks | 2 items | col 0 = 100px, col 1 = 200px |
| G-002 | P0 | §7.2 | grid-template-columns: 1fr 2fr fractional tracks | 300px container | col 0 = 100px, col 1 = 200px |
| G-003 | P0 | §7.2 | grid-template-columns: repeat(3, 1fr) | 300px container | 3 × 100px columns |
| G-004 | P0 | §7.2 | grid-template-rows same as above for rows | 3 explicit row sizes | Correct row heights |
| G-005 | P0 | §7.2 | grid-template-columns: minmax(100px, 200px) | 150px container | col = 150px (clamped) |
| G-006 | P0 | §7.2 | minmax(100px, 1fr) with available space | 400px, 2 cols: minmax(100,1fr) 200px | col 0 = 200px, col 1 = 200px |
| G-007 | P1 | §7.2 | auto track sizing | Items of varying size | Track sized to largest item |
| G-008 | P2 | §7.2 | fit-content(200px) track | Item with 150px content | Track = 150px (not 200px) |
2.2 Item Placement
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| G-010 | P0 | §8.1 | grid-column: 1 / 3 spanning | 3-col grid, item spans 2 | Item width = col 1 + col 2 |
| G-011 | P0 | §8.1 | grid-row: 2 / 4 spanning | 4-row grid, item spans rows 2–3 | Item height = row 2 + row 3 |
| G-012 | P0 | §8.3 | Auto-placement fills in order | 6 items, 3-col grid | 2 rows of 3 |
| G-013 | P1 | §8.1 | Negative line numbers | grid-column: -1 / -3 in 4-col grid | Spans last 2 columns |
| G-014 | P1 | §8.1 | grid-column: span 2 shorthand | Item with span 2 | Covers 2 column tracks |
2.3 Named Areas
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| G-020 | P1 | §7.3 | grid-template-areas with named regions | "header header" "nav main" | header spans full width, nav + main below |
| G-021 | P1 | §7.3 | grid-area: header places item into named area | Element with grid-area: header | Placed at row 1, cols 1–2 |
2.4 Gaps & Alignment
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| G-030 | P0 | Box Alignment §8 | gap: 10px between tracks | 3×3 grid with 10px gap | 10px between all tracks |
| G-031 | P1 | Box Alignment §8 | row-gap ≠ column-gap | Different gap values | Correct per-axis spacing |
| G-032 | P1 | §10.1 | justify-items: center | Items smaller than cell | Centered in each cell |
| G-033 | P1 | §10.1 | align-items: end | Items shorter than cell | Aligned to bottom of each cell |
3 Inline Formatting Context (CSS Text, CSS Inline, UAX #9, UAX #14)
3.1 Line Breaking
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| I-001 | P0 | UAX #14 | Break at word boundaries | Long sentence in 200px container | Words not split mid-word |
| I-002 | P0 | CSS Text §5 | word-wrap: break-word breaks long words | "Supercalifragilisticexpialidocious" in 100px | Word broken to fit |
| I-003 | P1 | UAX #14 | Break after hyphen | "state-of-the-art" in narrow container | Break at hyphens |
| I-004 | P1 | CSS Text §5 | CJK character breaking (each char is break opportunity) | Chinese text in narrow container | Breaks between any two characters |
| I-005 | P2 | CSS Text §5 | overflow-wrap: anywhere vs break-word | Long URL in narrow container | Break anywhere when needed |
3.2 BiDi (UAX #9)
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| I-010 | P0 | UAX #9 §3.3 | LTR paragraph base direction | English text | Left-to-right run order |
| I-011 | P0 | UAX #9 §3.3 | RTL paragraph base direction | Arabic text with dir="rtl" | Right-to-left run order |
| I-012 | P1 | UAX #9 §3.4 | Mixed LTR+RTL in single paragraph | English with embedded Arabic | Arabic segment visually reversed |
| I-013 | P1 | UAX #9 §3.4 | Nested BiDi embeddings | LTR > RTL > LTR nesting | Correct per-level reordering |
| I-014 | P2 | UAX #9 | Neutral characters between runs | Spaces and punctuation between LTR/RTL | Neutrals follow surrounding direction |
3.3 Vertical Alignment
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| I-020 | P0 | CSS Inline §4 | vertical-align: baseline (default) | Mixed font sizes on one line | Baselines aligned |
| I-021 | P1 | CSS Inline §4 | vertical-align: top / bottom | Inline element with v-align top | Aligned to line box top |
| I-022 | P1 | CSS Inline §4 | vertical-align: middle | Image in text line | Image centered on x-height |
| I-023 | P1 | CSS Inline §4 | line-height affects line box height | line-height: 2 on text | Line box = 2 × font-size |
4 Block Formatting Context (CSS Box Model Level 3)
4.1 Box Model
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| B-001 | P0 | §8 | Margin / padding / border applied correctly | margin: 10px; padding: 5px; border: 2px | Content offset by 17px from container |
| B-002 | P0 | §8.3 | Margin collapsing between siblings | Two blocks with margin 20px each | 20px gap (not 40px) |
| B-003 | P0 | §8.3 | Margin collapsing parent-child | Parent no padding/border, child margin-top 20px | Parent shifts down by 20px |
| B-004 | P1 | §8.3 | Padding/border prevents margin collapse | Parent with 1px border, child margin-top 20px | Child 20px inside parent |
| B-005 | P0 | §10.2 | box-sizing: content-box (default) | Width 200px, padding 10px, border 2px | Total = 224px |
| B-006 | P0 | §10.2 | box-sizing: border-box | Width 200px, padding 10px, border 2px | Total = 200px, content = 176px |
4.2 Sizing
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| B-010 | P0 | §10.3 | width: auto fills containing block | Block in 400px container | Width = 400px − margins |
| B-011 | P0 | §10.6 | height: auto shrinks to content | Block with 3 × 50px children | Height = 150px |
| B-012 | P0 | §10.4 | Percentage width resolves to parent | width: 50% in 400px container | Width = 200px |
| B-013 | P1 | §10.4 | min-width / max-width clamp | Width 100px, min-width 150px | Actual = 150px |
| B-014 | P1 | §10.7 | min-height / max-height clamp | Height 300px, max-height 200px | Actual = 200px |
4.3 Positioning
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| B-020 | P0 | §9.3 | position: relative offsets from normal position | top: 10px; left: 20px | Visual offset, siblings unaffected |
| B-021 | P0 | §9.6 | position: absolute removes from flow | Absolute child in relative parent | Positioned relative to parent |
| B-022 | P1 | §9.6 | Absolute with top/right/bottom/left | All four insets specified | Correctly sized and placed |
| B-023 | P1 | §9.6 | position: fixed relative to viewport | Fixed element | Positioned relative to viewport (ICB) |
4.4 Overflow
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| B-030 | P0 | CSS Overflow §3 | overflow: hidden clips content | Child taller than parent with overflow hidden | Child visually clipped |
| B-031 | P1 | CSS Overflow §3 | overflow: scroll provides scrollbar | Same as above with overflow scroll | Scrollable area created |
| B-032 | P1 | CSS Overflow §3 | overflow: auto only scrolls when needed | Content fits vs. overflows | Scrollbar only when needed |
5 CSS Intrinsic Sizing (CSS Intrinsic & Extrinsic Sizing Level 3)
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| S-001 | P1 | §4.1 | min-content width | Flex/grid child with width: min-content | Width = widest unbreakable word |
| S-002 | P1 | §4.2 | max-content width | Same with width: max-content | Width = full unwrapped line |
| S-003 | P2 | §4.3 | fit-content(200px) | Block with fit-content | Width = min(max-content, max(min-content, 200px)) |
6 Visual / Paint (CSS Backgrounds, Borders, Outlines)
| ID | Priority | Spec § | Description | Input Sketch | Expected |
|---|---|---|---|---|---|
| V-001 | P0 | CSS BG §5 | border-radius renders rounded corners | border-radius: 10px | Rounded corners visible |
| V-002 | P0 | CSS BG §3 | background-color fills content + padding | Blue background with padding | Color extends to padding edge |
| V-003 | P1 | CSS UI §4 | outline does not affect layout | outline: 2px solid red | No box model impact |
| V-004 | P1 | CSS UI §4 | outline-offset: 5px | Outline with offset | 5px gap between border and outline |
| V-005 | P1 | CSS BG §5 | border-style: dashed / dotted / double | Various border styles | Correct rendering per style |
| V-006 | P2 | CSS Masking | clip-path: circle(50%) | Circular clip on element | Content clipped to circle |
Running Tests
- Manniquin: Each test case should produce a reference image via Chrome and a test image via AperturePlayer. Manniquin compares pixel-by-pixel with a configurable tolerance (default 1% pixel diff threshold).
- Layout Unit Tests: For pure layout validation (no paint), compare
LayoutBoxoutput fields directly:- Position:
x,yrelative to containing block - Size:
width,height(content box or border box depending onbox-sizing) - Box model:
margin_top/right/bottom/left,padding_top/right/bottom/left,border_top/right/bottom/left - Flex:
flex_grow,flex_shrink,flex_basis,order
- Position:
- Test HTML files: Place in
Data/UnitTests/Layout/with naming convention{ID}.html(e.g.,F-001.html). - Regression Gate: All P0 tests must pass before merging layout changes. P1 tests are tracked as known issues if failing.

