v1.4.4 — Chromium Visual Parity
Ironpress now achieves 100% verified visual parity with Chromium across a 1,662-fixture adversarial corpus (1,642 PASS / 0 FAIL / 20 reference-disputed). Every fixture comparison uses the same pinned pdftoppm invocation at 300 DPI — no translation, registration, jitter, or raster replacement.
- Same-rasterizer parity gate:
scripts/parity.shrenders every fixture in-process, rasterizes candidate and oracle PDFs symmetrically, and reports pass/fail with complete RGBA evidence. refs.lockauthenticates each fixture, oracle PDF, renderer, fonts, and provenance.baseline.jsontracks regression health separately from test history.- HTML parity report with full visual diffs for every fixture.
- CI gate (
.github/workflows/parity.yml) runs the same browser-free check.
- Paged media:
@pagebackgrounds cascade through named,:first,:left,:right, and:blankselectors; sheet decoration modeled semantically. - Multicol: block flow constraints, nested clip paths, rule positioning, and layout split by semantic responsibility.
- Grid: block-size constrained before track alignment; multicol reference geometry corrected.
- Borders: collapsed table borders resolved as a shared grid; opaque square painting unified; rounded background coverage aligned; vector serialization matches Chromium; bevel geometry matched.
- Filters: inherited filter layer paint space; premultiplied source rendering; raster placement and sampling; linear-light surface parity; descendant clipping to overflow bounds.
- Inline layout: mixed advances unified; atomic inline origins preserved; generated content traversal unified; layout probes replaced with capabilities.
- Text: origin-aware text decorations; text combine expansion handling.
- Tables: cell paint phase ordering; expanded table height honored in flex alignment.
- Images: source pixels preserved for
object-fit: cover; source images reused across page fragments; fragmented JPEG background ownership; certificate image rendering optimized. - Backgrounds: nested fills routed through box background geometry; rounded raster phase fixed; full-box radial masks rendered as native shadings.
- Graphical effects: continued across page boxes; transformed descendants composited in filter sources.
- Transforms: Fontations transform oracle restored; fractional transform parity; CSS print scale reconstructed exactly.
- Raster: bounds quantized from exact DPI; x-height quantization matched with Fontations.
- List markers: built-in markers rendered as vector shapes.
- Opacity: applied to absolute-positioned elements.
RasterQualitystruct: controls background, filter, and image DPI in one policy. CLI exposes--image-dpi,--filter-dpi,--background-raster-dpi.
- 3,500+ unit tests (up from 2,200+)
- 1,662-fixture parity corpus with same-rasterizer verification
Full changelog: https://github.com/gastongouron/ironpress/blob/main/CHANGELOG.md
v1.4.1
- Module split:
engine.rs(16,500 lines) → 12 focused modules (block, flex, grid, table, text, images, helpers, paginate, inline, context) - LayoutContext: single struct replacing scattered width/height/containing-block parameters
- LayoutEnv: bundles rules, fonts, counter_state (-3 params per function)
- CSS descendant selectors in text runs (
pre code,div span) now match correctly margin-left/margin-righton block elements properly reduces width and offsets- Borders in flex containers — 4 rendering paths fixed (nested TextBlocks, TableRows, Container children, merged flex cells)
float: rightnow positions elements at the right edge (Container + TextBlock)- Percentage
widthresolves against layout parent, not style-time parent (fixes skill bars, progress indicators) - Inline text spacing — single BT/ET block per line eliminates cumulative positioning errors
- Times-Roman font metrics — proper AFM widths replace Helvetica approximation
vw/vhunits resolve against actual page size, not hardcoded A4- SVG
clip-pathnow works on shape elements (rect, circle, path), not just groups - List indentation uses
padding-leftmatching Chrome UA (user CSSpadding-left: 0works)
- Box-shadow blur — multi-layer concentric approximation replacing solid rectangles
- Python binding —
pip install ironpress(PyO3 + maturin) - Ruby binding —
gem install ironpress(Magnus)
- 2,170+ tests (up from 2,081)
- 93% line coverage
v1.4.0 — Chromium Parity Round 2 & 3
- Correct CSS→PDF Y-axis flip for rotate, translate, and composed matrix transforms
- Support
scaleX(),scaleY(),translateX(),translateY(),skew(),skewX(),skewY() - Chained transforms composed into single affine matrix
- viewBox placement fixed in flex cell nested elements (fixes invoice logo)
- Quadratic bezier (Q/T) path commands converted to proper cubic curves
radialGradientsupport with objectBoundingBox and userSpaceOnUsetext-anchorattribute (start, middle, end)
- Inline-block shrink-to-fit width (fixes pill shapes taking full width)
- Flex-grow second pass relayout for percentage-width children (progress bars)
- Separate flex-basis from child layout width (fixes flex-wrap with
flex: 1)
- Grid rows wrapped in Container for border + padding around all rows
- Cell backgrounds and borders offset by container padding
border-radius: 50%percentage resolution (circles)- Rounded rect background + border stroke for FlexCell elements
- Absolute
::before/::afterpositioned from container top (not mutated cursor) - Skip inline text collection to prevent double-rendering
- Container height constrained for
overflow: hidden - Unicode character width estimates for CJK, emoji, Hebrew, Arabic, Greek
dir="rtl"attribute support
- Compare ALL pages per fixture, not just page 1
- Visual diff images (red = different, white = identical)
- Fixed ImageMagick
compareexit code handling
workflow_dispatchtrigger for manual deploys- apt package caching, lighter font packages