Skip to content

CSS 2.1 test parity: floats, positioning, z-index gap (stacked on #263) - #264

Merged
eXpl0it3r merged 4 commits into
ArthurHub:masterfrom
jhaygood86:feature/css21-float-position-zindex
Nov 9, 2026
Merged

eXpl0it3r merged 4 commits into
ArthurHub:masterfrom
jhaygood86:feature/css21-float-position-zindex

Conversation

@jhaygood86

Copy link
Copy Markdown
Contributor

Stacked on #263 - the diff below includes that PR's commits too until it merges. Only the last 3 commits (float/clear, positioning, z-index) are this PR's own.

Summary

Part 1 of a CSS 2.1 test-parity sweep against PeachPDF's Integration test suite. Scope: chapter 9 (visual formatting model) — floats/clear, positioning, z-index.

  • Floats/clear: FloatPropertyTests.cs's doc comment claimed this fork had no clear property at all, dropping every clear case from the PeachPDF source it was ported from - that predates ClearProperty being added. Restored the parsing coverage, and ported PeachPDF's FloatLayoutRegressionTests.cs + the float/clear Acid2 cases as a new IntegrationTest/Layout/FloatLayoutIntegrationTests.cs (11 tests). All passed unmodified against this fork's existing float engine.
  • Positioning: position:relative had zero layout effect anywhere in this fork (parsed, never read); position:absolute only had ad-hoc partial support; position:fixed ignored the box's own margin; right/bottom were parsed at the CSS-OM level but never dispatched onto a box under any positioning scheme. Backported PeachPDF's CommitBlockChildOffset placement logic (adapted to this fork's box-places-itself layout shape) — see the second commit's message for the full breakdown, including two genuine pre-existing bugs in GetMinMaxSumWords that porting PeachPDF's shrink-to-fit-width tests surfaced and that PeachPDF had already fixed. Ported the CSS 2.1 §9.4.3/§10.3.7 Acid2 regression tests; all 9 pass.
  • z-index/stacking context: confirmed unimplemented (no ZIndex box property, no paint-order sorting anywhere in Core — FragmentPainter.cs already documents this as deferred follow-on work). Ported PeachPDF's Acid2 z-index regression test [Ignore]d with an accurate explanation, rather than building a separate, larger stacking-context feature into this PR.

Test plan

  • HtmlRenderer.Test full suite: 2432 passed, 0 failed
  • HtmlRenderer.IntegrationTest full suite: 357 passed, 0 failed (90 skipped, all pre-existing or the one new documented z-index gap)
  • HtmlRenderer.PdfSharp.Test full suite: 39 passed, 0 failed
  • Full solution (HtmlRenderer.sln) builds clean across net8.0, net8.0-windows, netstandard2.0, net462
  • Re-approved one baseline PDF (Tables.png) whose auto-width table column renders 1-2px differently now that the GetMinMaxSumWords fix applies generally — reviewed the diff image, confirmed it's the intended correction, not a regression

@eXpl0it3r

Copy link
Copy Markdown
Collaborator

Rebased onto the updated #263 and added one fix on top:

  • When a later layout pass resumes inside a position:relative box, top was taken from Location.Y, which already includes the relative offset, and then the offset got applied a second time. It now backs out RelativeOffsetY first. PositionRelative_WithAForcedBreakInside_AppliesTheOffsetOnce covers it.
  • The ignored z-index test matched the draw calls by location, but both boxes sit at (0,0), so both FindIndex calls returned the same rect and the test could never pass, even with z-index implemented. It now matches by color, like the PeachPDF original, and I shortened the [Ignore] reason. I checked it with the [Ignore] removed and it fails on the paint order, as it should.

@eXpl0it3r eXpl0it3r added the CSS label Nov 9, 2026
jhaygood86 and others added 4 commits November 9, 2026 09:08
FloatPropertyTests.cs claimed this fork had no clear CSS property at
all, dropping every clear case from the PeachPDF source it was ported
from - that predates ClearProperty being added and is now false, so
restore the parsing coverage. Ports PeachPDF's FloatLayoutRegression-
Tests.cs and the float/clear Acid2 regression cases as a new
IntegrationTest suite; all pass unmodified, confirming float/clear
layout parity with PeachPDF.
…/§10.3.7

position:relative previously had no layout effect anywhere in this
fork (parsed but never read); position:absolute only had ad-hoc
partial support (no real containing-block resolution, plain in-flow
placement otherwise); position:fixed resolved only against the page
and dropped the box's own margin; and `right`/`bottom` were parsed at
the CSS-OM level but never dispatched onto a box at all, so they had
zero effect under any positioning scheme.

Backports PeachPDF's CommitBlockChildOffset placement logic, adapted
to this fork's box places-itself (rather than parent-commits-child)
layout shape:
  - Right/Bottom become real box properties, wired through CssUtils
    the same way Left/Top already were.
  - position:relative applies a near/far offset (left wins over right
    when both are set, sign-flipped when only the far edge is) that is
    purely visual per §9.4.3: RelativeOffsetX/Y record it separately so
    the new StaticBottom can back it out again, and every sibling-
    placement/margin-collapse/shrink-to-fit call site that used to read
    a box's ActualBottom directly now reads StaticBottom instead, so a
    relatively-positioned box's offset no longer drags its parent's
    auto height or following siblings down with it.
  - position:absolute resolves against DomUtils.GetNearestPositioned-
    Ancestor's padding edge, on both axes anchoring from whichever of
    the near/far offset is set (right-anchoring reads the box's own
    already-resolved Size.Width; bottom-anchoring has to wait until
    this box's own ApplyHeight has run, since auto height depends on
    this box's own content, so it's corrected via a post-hoc OffsetTop
    shift instead of resolved inline like every other case here).
    Absolute boxes with width:auto also now shrink-to-fit their
    content instead of filling the containing block, matching CSS 2.1
    §10.3.7's common case (the full seven-case width-auto-resolution
    algorithm is not implemented).
  - position:fixed's offset is now computed once, in PerformLayoutImp
    once margin/container are guaranteed ready, instead of eagerly from
    the Left/Top property setters - which used to race ahead of
    ActualMarginLeft/Top being resolved and cache a margin-less
    Location that never got recomputed.

Porting PeachPDF's shrink-to-fit width tests also surfaced two real,
pre-existing bugs in GetMinMaxSumWords (a border/padding sum that
never reset between sibling "lines", and no explicit-width floor for
a childless block), both already fixed in PeachPDF - backported here
too, and re-approves one baseline PDF whose auto-width table column
render 1-2px differently now that the fix applies generally, not just
to the new absolute-positioning case that surfaced it.

Ports the CSS 2.1 §9.4.3/§10.3.7 Acid2 regression tests from PeachPDF
covering all of the above; all 9 pass.
…by-design test

Ports PeachPDF's Acid2 z-index/stacking regression test (CSS 2.1
§9.9/Appendix E: a position:relative;z-index:2 box must paint over a
later position:fixed sibling regardless of document order). Left
[Ignore]d rather than implemented: FragmentPainter.cs already
documents stacking-context paint order as deferred follow-on work,
and there is no ZIndex box property or paint-order sorting anywhere
in Core to hang a real implementation off of - this is a separate,
larger feature port, not a one-line fix like the positioning gaps
fixed in the previous commit.
Also match the z-index test's draw calls by color, so it can pass once stacking order is implemented.
@eXpl0it3r
eXpl0it3r force-pushed the feature/css21-float-position-zindex branch from 86dd7f1 to b7d7fcf Compare November 9, 2026 08:09
@eXpl0it3r
eXpl0it3r merged commit 11cb42b into ArthurHub:master Nov 9, 2026
9 checks passed
@eXpl0it3r

Copy link
Copy Markdown
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants