From bc1062d1b0ff292d705bc2ec2e718d08ec5e7c25 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Thu, 17 Sep 2026 11:30:59 +0200 Subject: [PATCH 1/5] Updated changelog --- CHANGELOG.md | 6 ++++++ src/AngleSharp.Renderer.Docs/package.json | 2 +- src/Directory.Build.props | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c926c3f..7d0a25a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.7.0 + +Released on ?. + +- (tbd) + # 0.6.0 Released on Wednesday, September 16 2026. diff --git a/src/AngleSharp.Renderer.Docs/package.json b/src/AngleSharp.Renderer.Docs/package.json index 52d30a3..c9a3d89 100644 --- a/src/AngleSharp.Renderer.Docs/package.json +++ b/src/AngleSharp.Renderer.Docs/package.json @@ -1,6 +1,6 @@ { "name": "@anglesharp/renderer", - "version": "0.6.0", + "version": "0.7.0", "preview": true, "description": "The doclet for the AngleSharp.Renderer documentation.", "keywords": [ diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 07ae44d..6bb8870 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,7 +2,7 @@ Adds rendering functionality to the core AngleSharp library. AngleSharp.Renderer - 0.6.0 + 0.7.0 enable latest true From 596aa41b7feb30c41c7b80296433f22034824c4b Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Thu, 17 Sep 2026 14:09:45 +0200 Subject: [PATCH 2/5] Implemented milestone issues --- CHANGELOG.md | 14 +- .../HtmlRendererTests.cs | 1245 ++++++++++++++- .../test02-typography-inline.png | Bin 99472 -> 99493 bytes ...ed-text-sizes-styles-decorations.linux.png | Bin 3888 -> 4049 bytes .../CssAnimationTracker.cs | 51 +- src/AngleSharp.Renderer/HtmlRenderer.cs | 1385 ++++++++++++++++- .../Rendering/DisplayList.cs | 21 + .../Rendering/RenderClipShape.cs | 21 + .../Skia/SkiaRenderBackend.cs | 71 + .../Skia/Svg/SvgFilterBuilder.cs | 142 +- 10 files changed, 2842 insertions(+), 108 deletions(-) create mode 100644 src/AngleSharp.Renderer/Rendering/RenderClipShape.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d0a25a..68c748f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,19 @@ Released on ?. -- (tbd) +- Improved regression test coverage for 3D CSS transform functions (`rotateX`/`rotateY`/`rotate3d`/`translate3d`/`scale3d`/`matrix3d`) (#16) +- Fixed `repeat(auto-fill/auto-fit)` fill-count resolution to use available space, gap, and track minimum size (#20) +- Fixed a pre-existing inline layout bug where plain, unstyled semantic inline elements (``, ``, ``, ``, ...) were misidentified as block-level, preventing them from sharing a line with sibling text (#23) +- Added support for `animation-play-state: paused` (#17) +- Added `aspect-ratio` width-from-height derivation for boxes with an auto width and definite height (#14) +- Added `object-fit` (`fill`/`contain`/`cover`/`none`/`scale-down`) and `object-position` support for replaced elements (#13) +- Added rendering support for `input[type=range]` (track + thumb) and `input[type=file]` (#21) +- Added `clip-path` support for ordinary HTML boxes (`circle()`, `ellipse()`, `inset()`, `polygon()`) (#12) +- Added `"""); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 100, + FontSize = 16f, + }); + + Assert.DoesNotContain(displayList.Commands, c => c is FillRectCommand f && f.Rect.Width == 1.5f); + } + + [Fact] + public async Task BuildDisplayList_FocusedTextAreaPaintsACaretOnTheLastWrappedLine() + { + var document = await ParseAsync(""""""); + var target = (IHtmlElement)document.GetElementById("target")!; + target.DoFocus(); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 100, + FontSize = 16f, + }); + + var caret = Assert.Single(displayList.Commands.OfType().Where(f => f.Rect.Width == 1.5f)); + var textCommands = displayList.Commands.OfType().OrderBy(t => t.Y).ToList(); + + Assert.True(textCommands.Count > 1); + + // The caret sits on the last wrapped line, below where the first line was painted - not + // pinned to the first line's own baseline. + Assert.True(caret.Rect.Y > textCommands[0].Y); + } + + [Fact] + public async Task BuildDisplayList_FocusedEmptyTextAreaPaintsACaretAtItsContentEdge() + { + var document = await ParseAsync(""""""); + var target = (IHtmlElement)document.GetElementById("target")!; + target.DoFocus(); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 100, + FontSize = 16f, + }); + + Assert.Single(displayList.Commands.OfType().Where(f => f.Rect.Width == 1.5f)); + } + + [Fact] + public async Task BuildDisplayList_FocusedTextAreaWithTrailingNewlineMovesCaretToANewEmptyLine() + { + var document = await ParseAsync(""" + + """); + var target = (IHtmlElement)document.GetElementById("target")!; + target.DoFocus(); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 100, + FontSize = 16f, + }); + + var caret = Assert.Single(displayList.Commands.OfType().Where(f => f.Rect.Width == 1.5f)); + var hiText = Assert.Single(displayList.Commands.OfType().Where(t => t.Text == "Hi")); + + // The trailing newline pushes the caret down onto its own, empty second line rather than + // leaving it right after "Hi" on the first line. + Assert.True(caret.Rect.Y > hiText.Y); + } + [Fact] public async Task BuildDisplayList_FocusedEmptyTextInputPaintsCaretAtTheContentEdge() { @@ -4417,6 +5127,76 @@ int CurrentCaretAlpha() Assert.Equal(255, CurrentCaretAlpha()); } + [Fact] + public async Task BuildDisplayList_RangeInputPaintsATrackAndAThumbPositionedByValue() + { + var document = await ParseAsync(""""""); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 100, + FontSize = 16f, + }); + + // The track: a thin, rounded gray bar spanning the control's own width. + var track = Assert.Single(displayList.Commands.OfType() + .Where(command => command.Rect.Width == 100f)); + Assert.False(track.Radii.IsZero); + + // The thumb: a small rounded square, its center at 25% along the track for value=25 out + // of a 0-100 range. + var thumb = Assert.Single(displayList.Commands.OfType() + .Where(command => command.Rect.Width < 100f && !command.Rect.Width.Equals(track.Rect.Width))); + var thumbCenterX = thumb.Rect.X + (thumb.Rect.Width / 2f); + Assert.Equal(25f, thumbCenterX, precision: 1); + } + + [Fact] + public async Task BuildDisplayList_RangeInputDefaultsToTheMidpointWhenValueIsUnset() + { + var document = await ParseAsync(""""""); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 100, + FontSize = 16f, + }); + + var track = Assert.Single(displayList.Commands.OfType().Where(c => c.Rect.Width == 100f)); + var thumb = Assert.Single(displayList.Commands.OfType().Where(c => c.Rect.Width < 100f && !c.Rect.Width.Equals(track.Rect.Width))); + var thumbCenterX = thumb.Rect.X + (thumb.Rect.Width / 2f); + + // No `value` authored - defaults to the (min+max)/2 midpoint (0-100 default range), so + // the thumb sits at 50% along the track. + Assert.Equal(50f, thumbCenterX, precision: 1); + } + + [Fact] + public async Task BuildDisplayList_FileInputGetsButtonLikeChromeAndAFixedLabel() + { + var document = await ParseAsync(""""""); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 100, + FontSize = 16f, + }); + + var label = Assert.Single(displayList.Commands.OfType().Where(t => t.Text == "Choose File")); + Assert.NotNull(label); + + // Button-like default chrome: a gray background box, matching FormControlKind.Button. + var background = Assert.Single(displayList.Commands.OfType() + .Where(command => command.Color.Equals(new RenderColor(0xe8, 0xe8, 0xe8)))); + Assert.True(background.Rect.Width > 0f); + } + [Fact] public async Task BuildDisplayList_UncheckedCheckboxPaintsOnlyItsBoxNoFill() { @@ -4908,28 +5688,119 @@ public async Task BuildDisplayList_ScaleTransformExpandsSymmetricallyAroundDefau } [Fact] - public async Task BuildDisplayList_MatrixFunctionPreservesAllSixComponents() + public async Task BuildDisplayList_RotateYProducesAnOrthographicHorizontalSquash() { - // The plain 6-value 2D matrix() form was previously confirmed to compute *wrong* values in - // AngleSharp.Css itself (a column-major-vs-row-major mismatch in how it padded the array - // passed to TransformMatrix's constructor) - now fixed upstream, with a reproducing test in - // AngleSharp.Css's own suite (TransformFunctionsTests.PlainSixValueMatrixFunctionPreservesAllSixComponents) - // confirming it. This renderer never guarded against that bug locally to begin with - per - // its own policy (see ParseCssTransform/ConvertToRenderTransform's remarks), it always - // trusts whatever AngleSharp.Css computes - so once AngleSharp.Css's own bug was fixed, - // matrix() started working correctly here automatically, with no change needed in this - // renderer at all. This test asserts the actual, now-correct values directly, using the - // same non-symmetric coefficients as AngleSharp.Css's own regression test specifically so a - // symmetric input could never mask a b/c transposition or an e/f loss the way it did before. + // Without a `perspective` in effect, this renderer flattens a 3D transform to 2D by + // evaluating its already-general matrix at z=0 and discarding the z-output - which for + // rotateY(theta) (rotation around the vertical axis) works out to a pure horizontal scale + // by cos(theta), with no foreshortening (matching how a browser renders 3D transforms with + // no perspective ancestor: an orthographic, not a perspective, projection). var document = await ParseAsync(""" -
+
"""); var renderer = new HtmlRenderer(); var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); - var push = Assert.Single(displayList.Commands.OfType()); - var t = push.Transform; + var t = Assert.Single(displayList.Commands.OfType()).Transform; + + Assert.Equal(0.5f, t.A, precision: 2); + Assert.Equal(0f, t.B, precision: 2); + Assert.Equal(0f, t.C, precision: 2); + Assert.Equal(1f, t.D, precision: 2); + } + + [Fact] + public async Task BuildDisplayList_RotateXProducesAnOrthographicVerticalSquash() + { + var document = await ParseAsync(""" + +
+ + """); + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + var t = Assert.Single(displayList.Commands.OfType()).Transform; + + Assert.Equal(1f, t.A, precision: 2); + Assert.Equal(0f, t.B, precision: 2); + Assert.Equal(0f, t.C, precision: 2); + Assert.Equal(0.5f, t.D, precision: 2); + } + + [Fact] + public async Task BuildDisplayList_TranslateZHasNoVisibleEffectWithoutPerspective() + { + // translateZ alone moves an element only along the axis perpendicular to the screen - + // with no perspective in effect to project that depth back onto the 2D plane, it has + // (correctly, matching a real browser with no `perspective` ancestor) no visible effect. + var document = await ParseAsync(""" + +
+ + """); + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + + Assert.Empty(displayList.Commands.OfType()); + } + + [Fact] + public async Task BuildDisplayList_Translate3DAppliesItsXAndYComponents() + { + var document = await ParseAsync(""" + +
+ + """); + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + var t = Assert.Single(displayList.Commands.OfType()).Transform; + + Assert.Equal(new RenderTransform2D(1f, 0f, 0f, 1f, 12f, 6f), t); + } + + [Fact] + public async Task BuildDisplayList_Scale3DAppliesItsXAndYComponents() + { + var document = await ParseAsync(""" + +
+ + """); + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + var t = Assert.Single(displayList.Commands.OfType()).Transform; + + Assert.Equal(2f, t.A, precision: 2); + Assert.Equal(0f, t.B, precision: 2); + Assert.Equal(0f, t.C, precision: 2); + Assert.Equal(3f, t.D, precision: 2); + } + + [Fact] + public async Task BuildDisplayList_MatrixFunctionPreservesAllSixComponents() + { + // The plain 6-value 2D matrix() form was previously confirmed to compute *wrong* values in + // AngleSharp.Css itself (a column-major-vs-row-major mismatch in how it padded the array + // passed to TransformMatrix's constructor) - now fixed upstream, with a reproducing test in + // AngleSharp.Css's own suite (TransformFunctionsTests.PlainSixValueMatrixFunctionPreservesAllSixComponents) + // confirming it. This renderer never guarded against that bug locally to begin with - per + // its own policy (see ParseCssTransform/ConvertToRenderTransform's remarks), it always + // trusts whatever AngleSharp.Css computes - so once AngleSharp.Css's own bug was fixed, + // matrix() started working correctly here automatically, with no change needed in this + // renderer at all. This test asserts the actual, now-correct values directly, using the + // same non-symmetric coefficients as AngleSharp.Css's own regression test specifically so a + // symmetric input could never mask a b/c transposition or an e/f loss the way it did before. + var document = await ParseAsync(""" + +
+ + """); + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + var push = Assert.Single(displayList.Commands.OfType()); + var t = push.Transform; Assert.Equal(2f, t.A, precision: 2); Assert.Equal(3f, t.B, precision: 2); @@ -5012,6 +5883,125 @@ public async Task BuildDisplayList_NoFilterProducesNoPushOrPopFilterCommands() Assert.Empty(displayList.Commands.OfType()); } + [Fact] + public async Task BuildDisplayList_ClipPathCircleClipsAnOrdinaryDivToACircleShape() + { + var document = await ParseAsync(""" + +
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + + var push = Assert.Single(displayList.Commands.OfType()); + var circle = Assert.IsType(push.Shape); + + Assert.Equal(50f, circle.CenterX, precision: 1); + Assert.Equal(30f, circle.CenterY, precision: 1); + Assert.Equal(20f, circle.Radius, precision: 1); + Assert.Single(displayList.Commands.OfType()); + } + + [Fact] + public async Task BuildDisplayList_ClipPathCircleDefaultsToCenteredClosestSideRadius() + { + var document = await ParseAsync(""" + +
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + + var push = Assert.Single(displayList.Commands.OfType()); + var circle = Assert.IsType(push.Shape); + + // No "at" clause -> centered (50,30); no explicit radius -> closest-side, which for a + // 100x60 box centered at (50,30) is the vertical distance to the nearest edge (30px). + Assert.Equal(50f, circle.CenterX, precision: 1); + Assert.Equal(30f, circle.CenterY, precision: 1); + Assert.Equal(30f, circle.Radius, precision: 1); + } + + [Fact] + public async Task BuildDisplayList_ClipPathEllipseResolvesIndependentXAndYRadii() + { + var document = await ParseAsync(""" + +
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + + var push = Assert.Single(displayList.Commands.OfType()); + var ellipse = Assert.IsType(push.Shape); + + Assert.Equal(50f, ellipse.CenterX, precision: 1); + Assert.Equal(30f, ellipse.CenterY, precision: 1); + Assert.Equal(40f, ellipse.RadiusX, precision: 1); + Assert.Equal(20f, ellipse.RadiusY, precision: 1); + } + + [Fact] + public async Task BuildDisplayList_ClipPathInsetShrinksTheClipRectFromEachEdge() + { + var document = await ParseAsync(""" + +
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + + var push = Assert.Single(displayList.Commands.OfType()); + var inset = Assert.IsType(push.Shape); + + Assert.Equal(15f, inset.Rect.X, precision: 1); + Assert.Equal(10f, inset.Rect.Y, precision: 1); + Assert.Equal(65f, inset.Rect.Width, precision: 1); + Assert.Equal(45f, inset.Rect.Height, precision: 1); + } + + [Fact] + public async Task BuildDisplayList_ClipPathPolygonProducesVerticesResolvedAgainstTheBox() + { + var document = await ParseAsync(""" + +
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + + var push = Assert.Single(displayList.Commands.OfType()); + var polygon = Assert.IsType(push.Shape); + + Assert.Equal(3, polygon.Points.Count); + Assert.Equal((0f, 0f), polygon.Points[0]); + Assert.Equal((100f, 0f), polygon.Points[1]); + Assert.Equal((50f, 60f), polygon.Points[2]); + } + + [Fact] + public async Task BuildDisplayList_NoClipPathProducesNoClipShapeCommands() + { + var document = await ParseAsync(""" + +
+ + """); + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice { ViewPortWidth = 200, ViewPortHeight = 200 }); + Assert.Empty(displayList.Commands.OfType()); + } + [Fact] public async Task BuildDisplayList_FilterNoneProducesNoPushOrPopFilterCommands() { @@ -5289,6 +6279,98 @@ public async Task BuildDisplayList_TextOverflowEllipsisHasNoEffectWithoutClippin Assert.Equal("This is a long line of text", text.Text); } + [Fact] + public async Task BuildDisplayList_WebkitLineClampTruncatesToNLinesWithEllipsisOnTheLast() + { + var document = await ParseAsync(""" + +
one two three four five six seven eight
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 200, + ViewPortHeight = 120, + FontSize = 16f, + }); + + var textCommands = displayList.Commands.OfType().OrderBy(t => t.Y).ToList(); + + // Clamped to exactly 2 lines - the remaining wrapped lines are dropped entirely, not just + // clipped/hidden. + Assert.Equal(2, textCommands.Count); + Assert.EndsWith("…", textCommands[1].Text); + } + + [Fact] + public async Task BuildDisplayList_WebkitLineClampHasNoEffectWhenTextFitsWithinTheLimit() + { + var document = await ParseAsync(""" + +
Short text
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 120, + FontSize = 16f, + }); + + var text = Assert.Single(displayList.Commands.OfType()); + Assert.Equal("Short text", text.Text); + Assert.DoesNotContain("…", text.Text); + } + + [Fact] + public async Task BuildDisplayList_WebkitLineClampHasNoEffectWithoutOverflowClipping() + { + var document = await ParseAsync(""" + +
one two three four five six seven eight
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 200, + ViewPortHeight = 120, + FontSize = 16f, + }); + + // No `overflow: hidden` - the clamp must not apply, matching the same "text-overflow has no + // effect without clipping" precedent already established for the single-line case. + var textCommands = displayList.Commands.OfType().ToList(); + Assert.True(textCommands.Count > 2); + Assert.DoesNotContain(textCommands, t => t.Text.Contains('…')); + } + + [Fact] + public async Task BuildDisplayList_WebkitLineClampWorksAcrossDifferentWidthsAndLineHeights() + { + var document = await ParseAsync(""" + +
one two three four five six
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 200, + ViewPortHeight = 120, + FontSize = 16f, + }); + + var text = Assert.Single(displayList.Commands.OfType()); + Assert.EndsWith("…", text.Text); + } + [Fact] public async Task BuildDisplayList_WordBreakAllWrapsAnOverlongWordAcrossMultipleLines() { @@ -5462,6 +6544,113 @@ public async Task BuildDisplayList_PseudoElementContentAttrResolvesHostAttribute Assert.Equal("Hello", texts[0].Text); } + [Fact] + public async Task BuildDisplayList_CounterIncrementNumbersSiblingElementsSequentially() + { + var document = await ParseAsync(""" + +
Alpha
+
Bravo
+
Charlie
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 200, + FontSize = 16f, + }); + + var texts = displayList.Commands.OfType().OrderBy(t => t.Y).Select(t => t.Text).ToArray(); + + // The trailing space in `". "` is trimmed away by the default `white-space: normal` + // rendering (the same trimming any other painted text gets), leaving just "N.". + Assert.Equal(["1.", "Alpha", "2.", "Bravo", "3.", "Charlie"], texts); + } + + [Fact] + public async Task BuildDisplayList_NestedCounterResetRestartsAndRestoresTheOuterCounter() + { + var document = await ParseAsync(""" + +
    +
  1. One +
      +
    1. One-A
    2. +
    3. One-B
    4. +
    +
  2. +
  3. Two
  4. +
+ + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 300, + FontSize = 16f, + }); + + var markerTexts = displayList.Commands.OfType() + .Where(t => t.Text.EndsWith('.')) + .OrderBy(t => t.Y) + .Select(t => t.Text) + .ToArray(); + + // The nested
    restarts its own "item" counter at 1 independently of the outer list, + // and the outer list's own counter correctly resumes at 2 for its second
  1. once the + // nested list's subtree has ended - not left at whatever value the nested list reached. + Assert.Equal(["1.", "1.", "2.", "2."], markerTexts); + } + + [Fact] + public async Task BuildDisplayList_CountersFunctionJoinsNestedCounterValuesWithASeparator() + { + var document = await ParseAsync(""" + +
      +
    1. One +
        +
      1. One-A
      2. +
      +
    2. +
    + + """); + + var renderer = new HtmlRenderer(); + var displayList = renderer.BuildDisplayList(document, new DefaultRenderDevice + { + ViewPortWidth = 300, + ViewPortHeight = 300, + FontSize = 16f, + }); + + var markerTexts = displayList.Commands.OfType() + .Where(t => t.Text is not ("One" or "One-A")) + .OrderBy(t => t.Y) + .Select(t => t.Text) + .ToArray(); + + Assert.Equal(["1", "1.1"], markerTexts); + } + [Fact] public async Task BuildDisplayList_PseudoElementInheritsColorFromHostWhenNotItselfSet() { diff --git a/src/AngleSharp.Renderer.Tests/rendered-cases/test02-typography-inline.png b/src/AngleSharp.Renderer.Tests/rendered-cases/test02-typography-inline.png index 0f8954e0e1fb3a5a50f091b023d44f176894d00e..a9f1f2cd5cca6f91b4c33bcf33340a6030397649 100644 GIT binary patch delta 60530 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

    @|yQ+RXHjHkn&E+S)SAcY2qKTJEE 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�r%1vRcJ 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 delta 60572 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 YNZqm@?V#ZcZV7cm@wP(dwR=zg4?Pk`J^%m! diff --git a/src/AngleSharp.Renderer.Tests/verification-assets/mixed-text-sizes-styles-decorations.linux.png b/src/AngleSharp.Renderer.Tests/verification-assets/mixed-text-sizes-styles-decorations.linux.png index f961687b45649321317dd2f9335010cfaad05fce..16aeb14ff20b314ab1a768c0f44b3c3daa7d6a38 100644 GIT binary patch literal 4049 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 LSi9`@!{`42T3~@1 literal 3888 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 PropertyValues); @@ -52,6 +53,14 @@ internal sealed class CssAnimationTracker { private readonly Dictionary<(IElement Element, string Name), double> _startTimesMs = []; + // Total virtual-clock time this (element, animation-name) pair has spent paused since it + // started, so it can be subtracted back out of the raw clock to get an "effective" clock that + // stays frozen for as long as the animation is paused and resumes in sync with the real clock + // once it isn't - the same amount of clock time always elapsing while paused as gets added + // here is what keeps the effective clock frozen across any number of paused observations. + private readonly Dictionary<(IElement Element, string Name), double> _pausedAccumulatedMs = []; + private readonly Dictionary<(IElement Element, string Name), double> _lastObservedClockMs = []; + ///

    /// Gets the animated value currently in effect for on /// , or null if no running `animation` on this element currently @@ -109,7 +118,8 @@ internal sealed class CssAnimationTracker } var startMs = _startTimesMs[(element, spec.Name)]; - var elapsedMs = clockMs - startMs - spec.DelayMs; + var effectiveClockMs = ResolveEffectiveClockMs(element, spec, clockMs); + var elapsedMs = effectiveClockMs - startMs - spec.DelayMs; var totalDurationMs = spec.DurationMs * spec.IterationCount; if (elapsedMs < 0d) @@ -150,6 +160,39 @@ internal sealed class CssAnimationTracker return InterpolateAtKeyframes(keyframes, property, eased); } + /// + /// `animation-play-state: paused` freezes an animation exactly where it currently is - not by + /// stopping the shared virtual clock (other animations/transitions on the same or other + /// elements must keep advancing normally), but by tracking how much clock time this specific + /// (element, animation-name) pair has spent paused and subtracting that back out of the raw + /// clock before the ordinary elapsed-time math runs. Whether the gap since the last observation + /// counts as paused time is decided by *this* call's play-state (not the previous one) - the + /// only state this tracker ever samples is at call time, so a pause taking effect anywhere + /// between two observations is attributed to the whole gap once it is next observed as paused; + /// once next observed as running again, no further time is added and the effective clock + /// continues advancing in lockstep with the real one from wherever it was left off. + /// + private double ResolveEffectiveClockMs(IElement element, CssAnimationSpec spec, double clockMs) + { + var key = (element, spec.Name); + + if (_lastObservedClockMs.TryGetValue(key, out var lastClockMs)) + { + if (spec.IsPaused) + { + _pausedAccumulatedMs[key] = _pausedAccumulatedMs.GetValueOrDefault(key) + (clockMs - lastClockMs); + } + } + else + { + _pausedAccumulatedMs[key] = 0d; + } + + _lastObservedClockMs[key] = clockMs; + + return clockMs - _pausedAccumulatedMs.GetValueOrDefault(key); + } + private static string? InterpolateAtKeyframes(IReadOnlyList stops, string property, double position) { if (position <= stops[0].Position) @@ -275,6 +318,7 @@ private static List ParseAnimationSpecs(ICssStyleDeclaration s var iterationList = HtmlRenderer.SplitTopLevelCommaList(style.GetPropertyValue("animation-iteration-count")); var directionList = HtmlRenderer.SplitTopLevelCommaList(style.GetPropertyValue("animation-direction")); var fillModeList = HtmlRenderer.SplitTopLevelCommaList(style.GetPropertyValue("animation-fill-mode")); + var playStateList = HtmlRenderer.SplitTopLevelCommaList(style.GetPropertyValue("animation-play-state")); var result = new List(nameList.Length); @@ -287,8 +331,9 @@ private static List ParseAnimationSpecs(ICssStyleDeclaration s var iterationCount = ParseIterationCount(ResolveListValue(iterationList, i, "1")); var direction = ParseDirection(ResolveListValue(directionList, i, "normal")); var fillMode = ParseFillMode(ResolveListValue(fillModeList, i, "none")); + var isPaused = string.Equals(ResolveListValue(playStateList, i, "running")?.Trim(), "paused", StringComparison.OrdinalIgnoreCase); - result.Add(new CssAnimationSpec(name, duration, delay, timingFunction, iterationCount, direction, fillMode)); + result.Add(new CssAnimationSpec(name, duration, delay, timingFunction, iterationCount, direction, fillMode, isPaused)); } return result; diff --git a/src/AngleSharp.Renderer/HtmlRenderer.cs b/src/AngleSharp.Renderer/HtmlRenderer.cs index 82823a1..08bbe39 100644 --- a/src/AngleSharp.Renderer/HtmlRenderer.cs +++ b/src/AngleSharp.Renderer/HtmlRenderer.cs @@ -72,7 +72,8 @@ private readonly record struct LayoutContext( ITextMeasurer TextMeasurer, FontFaceSet Fonts, Dictionary> StyleMapCache, - IStyleCollection? StyleCollection); + IStyleCollection? StyleCollection, + Dictionary> Counters); private sealed class LayoutCapture { @@ -236,7 +237,13 @@ private static LayoutContext CreateLayoutContext(IDocument document, IRenderDevi // must never be answered from a stale map computed on a previous call. See // GetOrCreateStyleMap's own remarks for why caching within a single call is safe. StyleMapCache: new Dictionary>(ReferenceEqualityComparer.Instance), - StyleCollection: styleCollection); + StyleCollection: styleCollection, + // CSS counters (`counter-reset`/`counter-increment`/`counter-set`, read by `counter()`/ + // `counters()` in `content`) are scoped to a single render exactly like StyleMapCache + // above - a fresh, empty stack set every call, never persisted across renders, so a + // counter's value can never leak between two separate BuildDisplayList calls for the + // same document (interactive re-renders included). + Counters: new Dictionary>()); } /// @@ -339,6 +346,16 @@ private static DisplayList BuildDisplayList(IDocument document, RenderViewport v PrepareDocumentForRendering(document); var renderTree = window.Render(renderDevice); + + // CSS counters (`counter-reset`/`counter-increment`/`counter-set`, read back by + // `counter()`/`counters()` in generated `content`) are resolved in a dedicated pre-pass + // over the already-built render tree, entirely independent of the actual layout walk below + // - plain recursive function calls give correct, automatic push/pop scoping for free (a + // counter-reset's own new instance is naturally "popped" back to whatever the enclosing + // scope had once this call returns), which the layout pass itself cannot offer cheaply + // given how many early-return paths LayoutElement has. See ProcessCounters' own remarks. + ProcessCounters(renderTree, context); + var body = document.Body; var root = body is null ? renderTree : renderTree.Find(body) ?? renderTree; @@ -356,7 +373,7 @@ private static DisplayList BuildDisplayList(IDocument document, RenderViewport v return displayList; } - var textStyle = new RenderTextStyle(context.FontSize, context.TextColor, context.FontFamily, context.LineHeightMultiplier, 400f, false, false, false, context.TextColor, global::AngleSharp.Renderer.Rendering.RenderTextDecorationStyle.Solid, TextAlign.Left, 0f, 0f, 0f, [], WhiteSpaceMode.Normal, WordBreakMode.Normal, OverflowWrapMode.Normal, TextOverflowMode.Clip); + var textStyle = new RenderTextStyle(context.FontSize, context.TextColor, context.FontFamily, context.LineHeightMultiplier, 400f, false, false, false, context.TextColor, global::AngleSharp.Renderer.Rendering.RenderTextDecorationStyle.Solid, TextAlign.Left, 0f, 0f, 0f, [], WhiteSpaceMode.Normal, WordBreakMode.Normal, OverflowWrapMode.Normal, TextOverflowMode.Clip, 0, TextDirection.Ltr); var cursorY = contentY; var previousBlockMarginBottom = 0f; var suppressNextBlockTopMargin = false; @@ -665,6 +682,34 @@ private static void LayoutElement( flexMainSize, flexCrossSize, propertyName: "width"); + + if (float.IsNaN(specifiedContentWidth) && !isFlexItem) + { + // A definite height plus `aspect-ratio` overrides a block-level box's normal + // "auto width fills the container" default - matching real browsers, and the same + // used-width/used-height "transferred size" relationship `aspect-ratio` already + // establishes in the other direction (see ResolveAspectRatioContentHeight, called + // further down once `height` is auto instead). Only applies when `width` is genuinely + // unauthored (not merely resolved to NaN through a flex/grid override, which already + // has its own, more specific sizing story this must not second-guess). + var heightReferenceForAspectRatio = float.IsNaN(containingHeight) ? flowContainingWidth : containingHeight; + var explicitContentHeight = ResolveAuthoredDimension( + styleMap, + "height", + heightReferenceForAspectRatio, + float.NaN, + borderTop + borderBottom + paddingTop + paddingBottom); + + if (!float.IsNaN(explicitContentHeight)) + { + specifiedContentWidth = ResolveAspectRatioContentWidth( + styleMap, + explicitContentHeight, + borderLeft + borderRight + paddingLeft + paddingRight, + borderTop + borderBottom + paddingTop + paddingBottom); + } + } + ResolveHorizontalMetrics( flowContainingWidth, specifiedContentWidth, @@ -1251,7 +1296,9 @@ private static void LayoutElement( var hasFilter = filterFunctions.Count > 0; var opacity = ParseCssOpacity(styleMap); var hasOpacity = opacity < 1f; - var createsStackingContext = HasExplicitZIndex(styleMap) || hasOpacity || hasTransform || hasFilter; + var clipPathShape = ParseClipPath(styleMap, borderBoxWidth, borderBoxHeight); + var hasClipPath = clipPathShape is not null; + var createsStackingContext = HasExplicitZIndex(styleMap) || hasOpacity || hasTransform || hasFilter || hasClipPath; var boxPaintBuffer = new DisplayList(); @@ -1282,6 +1329,18 @@ private static void LayoutElement( boxPaintBuffer.PushFilter(filterFunctions); } + // `clip-path` wraps the whole element too - background, border, outline, and every + // descendant are all clipped to the shape (unlike the overflow clip below, which excludes + // the border/outline it is nested inside) - nested innermost of the four whole-element + // scopes above, since its shape is expressed in the element's own already-transformed + // local space and should clip the filtered/opacity-composited result, not the other way + // around. + if (hasClipPath) + { + boxPaintBuffer.PushClipShape(clipPathShape!); + } + + PaintBackground(boxPaintBuffer, box.BackgroundPaint, borderBoxX, borderBoxY, borderBoxWidth, borderBoxHeight, box.BorderRadius); PaintBoxShadows(boxPaintBuffer, box.BoxShadows, borderBoxX, borderBoxY, borderBoxWidth, borderBoxHeight, box.BorderRadius); PaintBorder(boxPaintBuffer, box.BorderColor, borderBoxX, borderBoxY, borderBoxWidth, borderBoxHeight, box.BorderWidth, box.BorderRadius, box.BorderStyle); @@ -1310,9 +1369,19 @@ private static void LayoutElement( displayList.InsertRange(paintInsertionIndex, boxPaintBuffer.Commands); - if (TryResolveReplacedElementImage(node, styleMap, flowContainingWidth, borderBoxX + borderLeft + paddingLeft, borderBoxY + borderTop + paddingTop, out var image, out var imageRect)) + if (TryResolveReplacedElementImage(node, styleMap, flowContainingWidth, borderBoxX + borderLeft + paddingLeft, borderBoxY + borderTop + paddingTop, out var image, out var imageRect, out var objectFitClipRect)) { + if (objectFitClipRect is { } objectFitClip) + { + displayList.PushClip(objectFitClip, RenderCornerRadii.Zero); + } + displayList.DrawImage(imageRect, image!); + + if (objectFitClipRect is not null) + { + displayList.PopClip(); + } } if (clipsOverflow) @@ -1320,6 +1389,14 @@ private static void LayoutElement( displayList.PopClip(); } + // Closes the clip-path scope opened above, once children (and, for a replaced element, + // its image) have all been emitted - the innermost of the four whole-element scopes, so it + // closes before filter/opacity/transform do. + if (hasClipPath) + { + displayList.PopClip(); + } + // Closes the filter scope opened above, once children (and, for a replaced element, its // image) have all been emitted - nested inside the opacity scope, so it has to close // before that one does. @@ -1852,9 +1929,19 @@ private static void LayoutFlexContainer( displayList.InsertRange(boxPaintInsertIndex, boxPaintBuffer.Commands); - if (TryResolveReplacedElementImage(node, styleMap, containingWidth, borderBoxX + borderLeft + paddingLeft, borderBoxY + borderTop + paddingTop, out var image, out var imageRect)) + if (TryResolveReplacedElementImage(node, styleMap, containingWidth, borderBoxX + borderLeft + paddingLeft, borderBoxY + borderTop + paddingTop, out var image, out var imageRect, out var objectFitClipRect)) { + if (objectFitClipRect is { } objectFitClip) + { + displayList.PushClip(objectFitClip, RenderCornerRadii.Zero); + } + displayList.DrawImage(imageRect, image!); + + if (objectFitClipRect is not null) + { + displayList.PopClip(); + } } if (clipsOverflow) @@ -2415,14 +2502,6 @@ private static void LayoutGridContainer( // (and appended), so their paint commands are spliced in before this index instead. var boxPaintInsertIndex = displayList.Commands.Count; - var explicitGridTemplateColumns = ResolveExplicitPropertyValue(node.Ref, node.ComputedStyle, "grid-template-columns"); - var columns = ParseGridTrackListStructured(explicitGridTemplateColumns, containingWidth); - - if (columns.Count == 0) - { - columns.Add(GridTrackSize.Fixed(containingWidth)); - } - var columnGap = ParseGridGap(styleMap, "column-gap", containingWidth, 0) ?? ParseGridGap(styleMap, "gap", containingWidth, 0); var rowGap = ParseGridGap(styleMap, "row-gap", containingWidth, 0) @@ -2432,6 +2511,15 @@ private static void LayoutGridContainer( var gridItems = node.Children .Where(child => child is ElementRenderNode || (child is TextRenderNode textNode && NormalizeWhitespace(textNode.Ref.Data).Length > 0)) .ToList(); + + var explicitGridTemplateColumns = ResolveExplicitPropertyValue(node.Ref, node.ComputedStyle, "grid-template-columns"); + var columns = ParseGridTrackListStructured(explicitGridTemplateColumns, containingWidth, resolvedColumnGap, gridItems.Count); + + if (columns.Count == 0) + { + columns.Add(GridTrackSize.Fixed(containingWidth)); + } + var gridVerticalBorderAndPadding = borderTop + borderBottom + paddingTop + paddingBottom; var containerHeight = ResolveAuthoredDimension(styleMap, "height", containingWidth, float.NaN, gridVerticalBorderAndPadding); var explicitGridTemplateRows = ResolveExplicitPropertyValue(node.Ref, node.ComputedStyle, "grid-template-rows"); @@ -2867,27 +2955,128 @@ private static float GetGridTrackSpanSize(IReadOnlyList tracks, int index /// value - the caller falls back to a single implicit track, the same default a real browser /// gives an unstyled grid container. /// - private static List ParseGridTrackListStructured(string rawValue, float relativeTo) + private static List ParseGridTrackListStructured(string rawValue, float relativeTo, float gap = 0f, int itemCount = 0) { var tracks = new List(); + var trimmed = rawValue?.Trim() ?? string.Empty; - if (string.IsNullOrWhiteSpace(rawValue) || string.Equals(rawValue.Trim(), "none", StringComparison.OrdinalIgnoreCase)) + if (trimmed.Length == 0 || string.Equals(trimmed, "none", StringComparison.OrdinalIgnoreCase)) { return tracks; } - var source = new StringSource(rawValue.Trim()); + var source = new StringSource(trimmed); var parsed = source.ParseTrackList(); if (parsed is not null) { - AppendGridTracks(parsed, relativeTo, tracks); + AppendGridTracks(parsed, relativeTo, tracks, gap, itemCount); + return tracks; + } + + // AngleSharp.Css's own GridParser does not currently recognize the `auto-fill`/`auto-fit` + // repeat-count keywords at all (confirmed empirically: ParseTrackList returns null for the + // whole value, not just that one token) - a genuine upstream gap, worth reporting there, + // but one this renderer still needs to work around locally to support the single most + // common real-world use of `repeat()` (`repeat(auto-fill/auto-fit, ...)` as the entire + // track list). TryParseAutoRepeatTrackList hand-parses just that one shape; anything else + // that also failed to parse (a genuinely malformed value) still falls through to the empty + // list the caller already treats as "no explicit tracks". + if (TryParseAutoRepeatTrackList(trimmed, relativeTo, gap, itemCount, tracks)) + { + return tracks; } return tracks; } - private static void AppendGridTracks(ICssValue value, float relativeTo, List tracks) + /// + /// Hand-parses `repeat(auto-fill, <track-list>)`/`repeat(auto-fit, <track-list>)` as + /// the entire `grid-template-columns`/`-rows` value - locating the keyword by splitting on the + /// first top-level comma (one that is not itself nested inside the repeated track list's own + /// parentheses, e.g. `minmax(100px, 1fr)`'s comma), then delegating the repeated track list's + /// own structural parsing back to AngleSharp.Css's `GridParser` exactly as the normal path does - + /// only the outer auto-fill/auto-fit keyword recognition itself is hand-rolled. + /// + private static bool TryParseAutoRepeatTrackList(string trimmed, float relativeTo, float gap, int itemCount, List tracks) + { + if (!trimmed.StartsWith("repeat(", StringComparison.OrdinalIgnoreCase) || !trimmed.EndsWith(")", StringComparison.Ordinal)) + { + return false; + } + + var inner = trimmed[7..^1]; + var depth = 0; + var commaIndex = -1; + + for (var i = 0; i < inner.Length; i++) + { + switch (inner[i]) + { + case '(': + depth++; + break; + case ')': + depth--; + break; + case ',' when depth == 0: + commaIndex = i; + break; + } + + if (commaIndex >= 0) + { + break; + } + } + + if (commaIndex < 0) + { + return false; + } + + var keyword = inner[..commaIndex].Trim(); + var isAutoFill = string.Equals(keyword, "auto-fill", StringComparison.OrdinalIgnoreCase); + var isAutoFit = string.Equals(keyword, "auto-fit", StringComparison.OrdinalIgnoreCase); + + if (!isAutoFill && !isAutoFit) + { + return false; + } + + var trackListText = inner[(commaIndex + 1)..].Trim(); + var trackSource = new StringSource(trackListText); + var trackDefinition = trackSource.ParseTrackList(); + + if (trackDefinition is null) + { + return false; + } + + var groupMinSize = ResolveGridRepeatGroupMinSize(trackDefinition, relativeTo); + + if (groupMinSize <= 0f || float.IsNaN(relativeTo) || relativeTo <= 0f) + { + AppendGridTracks(trackDefinition, relativeTo, tracks, gap, itemCount); + return true; + } + + var fillCount = Math.Max(1, (int)Math.Floor((relativeTo + gap) / (groupMinSize + gap))); + + if (isAutoFit && itemCount > 0) + { + fillCount = Math.Max(1, Math.Min(fillCount, itemCount)); + } + + for (var i = 0; i < fillCount; i++) + { + AppendGridTracks(trackDefinition, relativeTo, tracks, gap, itemCount); + } + + return true; + } + + private static void AppendGridTracks(ICssValue value, float relativeTo, List tracks, float gap, int itemCount) { switch (value) { @@ -2901,11 +3090,11 @@ private static void AppendGridTracks(ICssValue value, float relativeTo, List - /// `repeat(auto-fill, ...)`/`repeat(auto-fit, ...)` need the container's own available space to - /// compute how many repetitions fit - a genuinely different, container-size-dependent algorithm - /// this renderer does not implement. Falls back to a single repetition (the count `1` never - /// causes a dropped track or a NaN/absurd count), a deliberate, documented scope cut. + /// `repeat(auto-fill, ...)`/`repeat(auto-fit, ...)` resolve their true fill count from the + /// container's own available space, the axis gap, and the repeated track group's own minimum + /// size - the same formula browsers use: floor((available + gap) / (groupMinSize + gap)), + /// clamped to at least one repetition. `auto-fit` additionally collapses empty trailing tracks: + /// the full spec algorithm does this after item placement (an empty track becomes a literal + /// zero-width, gap-less track), which this renderer approximates by capping the fill count at + /// the actual item count up front - close enough for the common single-row/auto-placement case, + /// though it does not reclaim space for an item that itself spans multiple tracks. `auto-fill` + /// keeps every computed track (empty or not), which is the whole difference between the two. /// - private static int ResolveGridRepeatCount(ICssValue countValue) + private static int ResolveGridRepeatCount(ICssValue countValue, ICssValue trackDefinition, float availableSize, float gap, int itemCount) { - var text = countValue.CssText; + var text = countValue.CssText.Trim(); + var isAutoFill = string.Equals(text, "auto-fill", StringComparison.OrdinalIgnoreCase); + var isAutoFit = string.Equals(text, "auto-fit", StringComparison.OrdinalIgnoreCase); + + if (isAutoFill || isAutoFit) + { + if (float.IsNaN(availableSize) || availableSize <= 0f) + { + return 1; + } + + var groupMinSize = ResolveGridRepeatGroupMinSize(trackDefinition, availableSize); + + if (groupMinSize <= 0f) + { + return 1; + } + + var fillCount = Math.Max(1, (int)Math.Floor((availableSize + gap) / (groupMinSize + gap))); + + if (isAutoFit && itemCount > 0) + { + fillCount = Math.Max(1, Math.Min(fillCount, itemCount)); + } + + return fillCount; + } if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var count)) { @@ -2945,6 +3165,27 @@ private static int ResolveGridRepeatCount(ICssValue countValue) return 1; } + /// + /// The minimum pixel footprint of one repetition of a `repeat(auto-fill/auto-fit, ...)`'s own + /// track list - a fixed length contributes its own size, `minmax(min, max)` contributes `min` + /// when it is itself a plain length (0 otherwise), and an `fr`/`auto` track contributes 0 (it + /// has no definite minimum to anchor the fill-count formula to) - a deliberate approximation of + /// the spec's own (considerably more involved) automatic-repeat-count algorithm, matching the + /// overwhelmingly common real-world pattern of `repeat(auto-fill/auto-fit, minmax(<length>, ...))`. + /// + private static float ResolveGridRepeatGroupMinSize(ICssValue trackDefinition, float relativeTo) => trackDefinition switch + { + CssTupleValue tuple => tuple.Items.Where(item => item is not null).Sum(item => ResolveGridTrackMinContribution(item!, relativeTo)), + _ => ResolveGridTrackMinContribution(trackDefinition, relativeTo), + }; + + private static float ResolveGridTrackMinContribution(ICssValue value, float relativeTo) => value switch + { + CssMinMaxValue minMax => minMax.Minimum is CssLengthValue ? ResolveGridTrackLength(minMax.Minimum, relativeTo) : 0f, + CssLengthValue => ResolveGridTrackLength(value, relativeTo), + _ => 0f, + }; + private static GridTrackSize ConvertGridTrackSize(ICssValue value, float relativeTo) { switch (value) @@ -3327,6 +3568,19 @@ private static void LayoutWrappedText( var lineHeight = textStyle.FontSize * textStyle.LineHeightMultiplier; var lines = WrapTextRespectingWhiteSpace(context, text, maxWidth, textStyle); + // `-webkit-line-clamp: N` truncates to at most N lines, with an ellipsis appended to the + // last kept line whenever there was more text than fit - the multi-line counterpart to + // `text-overflow: ellipsis`'s single-line truncation just above. The clamped-away lines + // are dropped entirely (not laid out at all, not just clipped/hidden), matching how a real + // browser's `-webkit-line-clamp` removes them from the box's own content height too. + var isClampedLastLine = false; + + if (textStyle.LineClamp > 0 && lines.Count > textStyle.LineClamp) + { + lines = [.. lines.Take(textStyle.LineClamp)]; + isClampedLastLine = true; + } + for (var index = 0; index < lines.Count; index++) { var line = lines[index]; @@ -3338,21 +3592,35 @@ private static void LayoutWrappedText( } // An empty line (a blank `pre`/`pre-wrap`/`pre-line` row from a run of consecutive - // forced breaks) still needs to advance cursorY above, but has nothing to measure/paint. - if (line.Length == 0) + // forced breaks) still needs to advance cursorY above, but has nothing to measure/paint + // - unless it is itself the clamped-to line, which still needs its own ellipsis. + if (line.Length == 0 && !(isClampedLastLine && index == lines.Count - 1)) { continue; } + // `direction: rtl`'s own visual-order reversal (see ParseTextDirection's remarks for + // this renderer's bidi scope) - reversing an already-wrapped line's own word sequence + // so the first logical word ends up rightmost, matching how a real browser lays out a + // pure-RTL paragraph. Deliberately word-level, not full UAX#9 character reordering: + // each word's own internal character order is left untouched, which is correct for a + // non-cursive script and a reasonable approximation for any other. + if (textStyle.Direction == TextDirection.Rtl) + { + line = ReverseWordOrder(line); + } + var lineWidth = MeasureTextWidth(context, line, textStyle); var lineMaxWidth = index == 0 ? Math.Max(0f, maxWidth - firstLineIndent) : maxWidth; + var isLastLine = index == lines.Count - 1; // `text-overflow: ellipsis` is scoped to the single-line case - by far the dominant // real-world usage (`overflow: hidden; white-space: nowrap; text-overflow: ellipsis`) - // rather than truncating the last of several wrapped lines, which the CSS spec itself - // does not define without a non-standard extension (`-webkit-line-clamp`); a genuinely - // multi-line result here (`lines.Count > 1`) is left as-is, matching that scope cut. - if (textStyle.TextOverflow == TextOverflowMode.Ellipsis && lines.Count == 1 && lineWidth > lineMaxWidth) + // does not define without the non-standard `-webkit-line-clamp` extension handled + // separately above; a genuinely multi-line, non-clamped result here is left as-is. + if ((isClampedLastLine && isLastLine) || + (textStyle.TextOverflow == TextOverflowMode.Ellipsis && lines.Count == 1 && lineWidth > lineMaxWidth)) { line = TruncateWithEllipsis(context, line, lineMaxWidth, textStyle); lineWidth = MeasureTextWidth(context, line, textStyle); @@ -3379,6 +3647,24 @@ private static void LayoutWrappedText( } } + /// + /// Reverses a single already-wrapped line's own word sequence, for `direction: rtl`'s + /// word-level visual reordering - see 's own call site remarks + /// for the scope this covers (and does not). + /// + private static string ReverseWordOrder(string line) + { + var words = line.Split(' ', StringSplitOptions.RemoveEmptyEntries); + + if (words.Length <= 1) + { + return line; + } + + Array.Reverse(words); + return string.Join(' ', words); + } + /// /// Splits into display lines, honoring white-space's two layout- /// relevant effects itself cannot: an @@ -3808,7 +4094,7 @@ private static float EstimateFlexItemMainSize(IRenderNode node, float crossSize, var styleMap = GetOrCreateStyleMap(context, element.Ref, element.ComputedStyle); var box = ResolveBoxStyle(styleMap, element.Ref); var contentWidth = Math.Max(1f, crossSize - box.BorderWidth.Left - box.BorderWidth.Right - box.Padding.Left - box.Padding.Right); - var textStyle = ResolveTextStyle(styleMap, new RenderTextStyle(16f, RenderColor.Black, "sans-serif", 1.2f, 400f, false, false, false, RenderColor.Black, global::AngleSharp.Renderer.Rendering.RenderTextDecorationStyle.Solid, TextAlign.Left, 0f, 0f, 0f, [], WhiteSpaceMode.Normal, WordBreakMode.Normal, OverflowWrapMode.Normal, TextOverflowMode.Clip)); + var textStyle = ResolveTextStyle(styleMap, new RenderTextStyle(16f, RenderColor.Black, "sans-serif", 1.2f, 400f, false, false, false, RenderColor.Black, global::AngleSharp.Renderer.Rendering.RenderTextDecorationStyle.Solid, TextAlign.Left, 0f, 0f, 0f, [], WhiteSpaceMode.Normal, WordBreakMode.Normal, OverflowWrapMode.Normal, TextOverflowMode.Clip, 0, TextDirection.Ltr)); var text = NormalizeWhitespace(element.Ref.TextContent ?? string.Empty, textStyle.WhiteSpace); var lineCount = text.Length == 0 ? 0 : WrapTextRespectingWhiteSpace(context, text, contentWidth, textStyle).Count; return lineCount * textStyle.FontSize * textStyle.LineHeightMultiplier; @@ -3822,7 +4108,7 @@ private static float EstimateFlexItemContentWidth(ElementRenderNode element, flo if (text.Length > 0) { - var textStyle = ResolveTextStyle(styleMap, new RenderTextStyle(16f, RenderColor.Black, "sans-serif", 1.2f, 400f, false, false, false, RenderColor.Black, global::AngleSharp.Renderer.Rendering.RenderTextDecorationStyle.Solid, TextAlign.Left, 0f, 0f, 0f, [], WhiteSpaceMode.Normal, WordBreakMode.Normal, OverflowWrapMode.Normal, TextOverflowMode.Clip)); + var textStyle = ResolveTextStyle(styleMap, new RenderTextStyle(16f, RenderColor.Black, "sans-serif", 1.2f, 400f, false, false, false, RenderColor.Black, global::AngleSharp.Renderer.Rendering.RenderTextDecorationStyle.Solid, TextAlign.Left, 0f, 0f, 0f, [], WhiteSpaceMode.Normal, WordBreakMode.Normal, OverflowWrapMode.Normal, TextOverflowMode.Clip, 0, TextDirection.Ltr)); contentWidth = MeasureTextWidth(context, text, textStyle); var maxWidth = ResolveAuthoredDimension(styleMap, "max-width", relativeTo, float.NaN, 0f); if (!float.IsNaN(maxWidth)) @@ -3877,7 +4163,23 @@ private static bool ShouldRenderAsBlock(ICssStyleDeclaration computedStyle, stri }; } - return !string.Equals(tagName, "code", StringComparison.OrdinalIgnoreCase); + // AngleSharp.Css's own UA stylesheet does not give every semantic inline tag (``, + // ``, ``, ``, ...) an explicit `display: inline` rule - `inline` is + // simply CSS's own initial value, so nothing ever needs to set it - which means + // `GetDisplay()` reports an empty string for a plain, unstyled one of these (the same + // "never serialized when nothing in the cascade set it explicitly" pattern already + // documented elsewhere in this file for `list-style-type`/`white-space`/etc.), not the + // literal word "inline". A real, confirmed bug (not hypothetical) fell out of that: this + // fallback used to treat every tag except `` as block-level whenever `display` came + // back empty, so a plain, zero-CSS ``/``/``/... was misidentified as + // block, which in turn made a parent's `hasInlineRun` merge-onto-shared-lines check (see + // `LayoutElement`) never trigger for it - `

    Hello World

    ` rendered "World" on + // its own separate line instead of beside "Hello". `IsKnownInlineElement` already + // enumerates every standard semantic inline tag (including ``, so that tag's own + // prior special case is now fully subsumed) for exactly this "no explicit display, still + // inline by default" situation - reusing it here, rather than only ever excluding ``, + // fixes every one of them at once. + return !(tagName is not null && IsKnownInlineElement(tagName)); } private static bool IsInlineBlock(ICssStyleDeclaration computedStyle) @@ -3925,7 +4227,8 @@ private static RenderTextStyle ResolveTextStyle(Dictionary style var (underline, strikeThrough) = ParseTextDecoration(styleMap, inherited.Underline, inherited.StrikeThrough); var decorationColor = ParseColor(styleMap.TryGetValue("text-decoration-color", out var decorationColorValue) ? decorationColorValue : null, color); var decorationStyle = ParseTextDecorationStyle(styleMap, inherited.DecorationStyle); - var textAlign = ParseTextAlign(styleMap, inherited.TextAlign); + var direction = ParseTextDirection(styleMap, inherited.Direction); + var textAlign = ParseTextAlign(styleMap, inherited.TextAlign, direction); var letterSpacing = ParseLength(styleMap, "letter-spacing", inherited.FontSize, inherited.LetterSpacing, allowAuto: false); var textIndent = ParseLength(styleMap, "text-indent", inherited.FontSize, 0f, allowAuto: false); var verticalAlignOffset = ParseVerticalAlign(styleMap, fontSize); @@ -3934,8 +4237,28 @@ private static RenderTextStyle ResolveTextStyle(Dictionary style var wordBreak = ParseWordBreak(styleMap, inherited.WordBreak); var overflowWrap = ParseOverflowWrap(styleMap, inherited.OverflowWrap); var textOverflow = ParseTextOverflow(styleMap); + var lineClamp = ParseLineClamp(styleMap); + + return new RenderTextStyle(fontSize, color, fontFamily, lineHeight, fontWeight, isItalic, underline, strikeThrough, decorationColor, decorationStyle, textAlign, letterSpacing, textIndent, verticalAlignOffset, textShadows, whiteSpace, wordBreak, overflowWrap, textOverflow, lineClamp, direction); + } + + /// + /// `direction` (`ltr`/`rtl`) is inherited, the same as `white-space`/`word-break` above. + /// `unicode-bidi` (which controls whether `direction` establishes a new embedding level versus + /// only affecting the current one) is not separately modeled - this renderer's own bidi support + /// is a single, document-wide-per-element `direction` flag driving word-order reversal and the + /// `start`/`end` text-align resolution below, not a full Unicode Bidirectional Algorithm (UAX#9) + /// implementation with embedding levels/overrides - a deliberate, documented scope cut matching + /// "supported by current architecture" rather than a from-scratch bidi engine. + /// + private static TextDirection ParseTextDirection(Dictionary styleMap, TextDirection inherited) + { + if (!styleMap.TryGetValue("direction", out var value) || string.IsNullOrWhiteSpace(value)) + { + return inherited; + } - return new RenderTextStyle(fontSize, color, fontFamily, lineHeight, fontWeight, isItalic, underline, strikeThrough, decorationColor, decorationStyle, textAlign, letterSpacing, textIndent, verticalAlignOffset, textShadows, whiteSpace, wordBreak, overflowWrap, textOverflow); + return string.Equals(value.Trim(), "rtl", StringComparison.OrdinalIgnoreCase) ? TextDirection.Rtl : TextDirection.Ltr; } /// @@ -4000,6 +4323,36 @@ private static TextOverflowMode ParseTextOverflow(Dictionary sty : TextOverflowMode.Clip; } + /// + /// `-webkit-line-clamp: <N>` (a long-standing, still-`-webkit-`-prefixed-only de facto + /// standard for multi-line truncation with an ellipsis on the final visible line - there is no + /// unprefixed equivalent in wide use, and it is what `text-overflow: ellipsis` itself has no + /// standard multi-line behavior without) - like `text-overflow`, never inherited (re-derived + /// fresh per element) and only meaningful on a box that itself clips overflow; unlike + /// `text-overflow`, this renderer does not additionally require `display: -webkit-box`/ + /// `-webkit-box-orient: vertical` (the other two properties real browsers also require) - a + /// deliberate, documented simplification, since this renderer has no multi-column/flex-like + /// `-webkit-box` layout mode of its own for those to meaningfully interact with; `overflow: + /// hidden` plus a positive integer is treated as sufficient signal on its own. Returns 0 + /// (unclamped) when unset, non-positive, or not a plain integer. + /// + private static int ParseLineClamp(Dictionary styleMap) + { + if (!ShouldClipOverflow(styleMap)) + { + return 0; + } + + if (!styleMap.TryGetValue("-webkit-line-clamp", out var value) || string.IsNullOrWhiteSpace(value)) + { + return 0; + } + + return int.TryParse(value.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var lineClamp) && lineClamp > 0 + ? lineClamp + : 0; + } + /// /// white-space is inherited (confirmed empirically - an unset value on a child reports /// empty, not the CSS initial normal, the same "never serialized when nothing in the @@ -4084,11 +4437,19 @@ _ when ParseLengthValue(normalized, float.NaN, allowAuto: false) is var offset & }; } - private static TextAlign ParseTextAlign(Dictionary styleMap, TextAlign defaultValue) + private static TextAlign ParseTextAlign(Dictionary styleMap, TextAlign defaultValue, TextDirection direction) { + var startAlign = direction == TextDirection.Rtl ? TextAlign.Right : TextAlign.Left; + var endAlign = direction == TextDirection.Rtl ? TextAlign.Left : TextAlign.Right; + if (!styleMap.TryGetValue("text-align", out var value) || string.IsNullOrWhiteSpace(value)) { - return defaultValue; + // `text-align`'s own CSS initial value is `start`, which - unlike this map's other + // properties - genuinely depends on `direction` rather than always meaning "left": + // `defaultValue` here is really only ever `TextAlign.Left`, the hardcoded assumption + // every call site made before `direction` was resolved at all, so it is superseded by + // `startAlign` whenever this element's own resolved direction is `rtl`. + return direction == TextDirection.Rtl ? startAlign : defaultValue; } var normalized = value.Trim().ToLowerInvariant(); @@ -4097,9 +4458,9 @@ private static TextAlign ParseTextAlign(Dictionary styleMap, Tex { "center" => TextAlign.Center, "right" => TextAlign.Right, - "end" => TextAlign.Right, + "end" => endAlign, "left" => TextAlign.Left, - "start" => TextAlign.Left, + "start" => startAlign, _ => defaultValue, }; } @@ -4518,6 +4879,9 @@ private static Dictionary CreateStyleMap(ICssStyleDeclaration st AddLengthProperty(map, style, "min-height", explicitDeclarations); AddLengthProperty(map, style, "max-height", explicitDeclarations); AddIfPresent(map, "box-sizing", style.GetBoxSizing()); + AddIfPresent(map, "object-fit", style.GetPropertyValue("object-fit")); + AddIfPresent(map, "object-position", style.GetPropertyValue("object-position")); + AddIfPresent(map, "clip-path", style.GetPropertyValue("clip-path")); var explicitAspectRatio = explicitDeclarations?.GetPropertyValue("aspect-ratio"); AddIfPresent(map, "aspect-ratio", string.IsNullOrWhiteSpace(explicitAspectRatio) ? style.GetPropertyValue("aspect-ratio") @@ -4566,6 +4930,9 @@ private static Dictionary CreateStyleMap(ICssStyleDeclaration st AddIfPresent(map, "list-style-type", style.GetPropertyValue("list-style-type")); AddIfPresent(map, "list-style-position", style.GetPropertyValue("list-style-position")); + AddIfPresent(map, "counter-reset", style.GetPropertyValue("counter-reset")); + AddIfPresent(map, "counter-increment", style.GetPropertyValue("counter-increment")); + AddIfPresent(map, "counter-set", style.GetPropertyValue("counter-set")); AddIfPresent(map, "overflow-x", style.GetPropertyValue("overflow-x")); AddIfPresent(map, "overflow-y", style.GetPropertyValue("overflow-y")); @@ -4683,13 +5050,31 @@ private static Dictionary CreateStyleMap(ICssStyleDeclaration st AddIfPresent(map, "text-decoration-color", style.GetPropertyValue("text-decoration-color")); AddIfPresent(map, "text-decoration-style", style.GetPropertyValue("text-decoration-style")); AddIfPresent(map, "text-align", style.GetPropertyValue("text-align")); + AddIfPresent(map, "direction", style.GetPropertyValue("direction")); AddLengthProperty(map, style, "text-indent"); AddIfPresent(map, "vertical-align", style.GetVerticalAlign()); AddLengthProperty(map, style, "letter-spacing"); AddIfPresent(map, "line-height", style.GetLineHeight()); AddIfPresent(map, "color", style.GetColor()); - AddIfPresent(map, "white-space", style.GetPropertyValue("white-space")); + // A real