diff --git a/Tests/LibWeb/Layout/expected/css-counters/basic.txt b/Tests/LibWeb/Layout/expected/css-counters/basic.txt new file mode 100644 index 0000000000000..7520271ecabbd --- /dev/null +++ b/Tests/LibWeb/Layout/expected/css-counters/basic.txt @@ -0,0 +1,134 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,16) content-size 784x314 children: not-inline + BlockContainer
at (8,16) content-size 784x149 children: not-inline + BlockContainer

at (8,16) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 5, rect: [37,16 44.75x17] baseline: 13.296875 + "Never" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,16 28.8125x17] baseline: 13.296875 + "1.1: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,49) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 5, rect: [39,49 52.15625x17] baseline: 13.296875 + "Gonna" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,49 31.28125x17] baseline: 13.296875 + "1.2: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,82) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 4, rect: [40,82 34.71875x17] baseline: 13.296875 + "Give" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,82 31.5625x17] baseline: 13.296875 + "1.3: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,115) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 3, rect: [38,115 31.21875x17] baseline: 13.296875 + "You" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,115 30.21875x17] baseline: 13.296875 + "1.4: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,148) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 2, rect: [39,148 20.71875x17] baseline: 13.296875 + "Up" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,148 30.921875x17] baseline: 13.296875 + "1.5: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,181) content-size 784x149 children: not-inline + BlockContainer

at (8,181) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 5, rect: [39,181 44.75x17] baseline: 13.296875 + "Never" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,181 31.28125x17] baseline: 13.296875 + "2.1: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,214) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 5, rect: [42,214 52.15625x17] baseline: 13.296875 + "Gonna" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,214 33.75x17] baseline: 13.296875 + "2.2: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,247) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 3, rect: [42,247 26.4375x17] baseline: 13.296875 + "Let" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,247 34.03125x17] baseline: 13.296875 + "2.3: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,280) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 3, rect: [41,280 31.21875x17] baseline: 13.296875 + "You" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,280 32.6875x17] baseline: 13.296875 + "2.4: " + TextNode <#text> + TextNode <#text> + BlockContainer

at (8,313) content-size 784x17 children: inline + frag 0 from TextNode start: 0, length: 4, rect: [41,313 42.328125x17] baseline: 13.296875 + "Down" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [8,313 33.390625x17] baseline: 13.296875 + "2.5: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (8,346) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x600] + PaintableWithLines (BlockContainer) [8,16 784x314] overflow: [8,16 784x330] + PaintableWithLines (BlockContainer

) [8,16 784x149] + PaintableWithLines (BlockContainer

) [8,16 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,49 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,82 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,115 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,148 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,181 784x149] + PaintableWithLines (BlockContainer

) [8,181 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,214 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,247 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,280 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer

) [8,313 784x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [8,346 784x0] diff --git a/Tests/LibWeb/Layout/expected/css-counters/counters-function.txt b/Tests/LibWeb/Layout/expected/css-counters/counters-function.txt new file mode 100644 index 0000000000000..13f00b57ec17d --- /dev/null +++ b/Tests/LibWeb/Layout/expected/css-counters/counters-function.txt @@ -0,0 +1,254 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x255 children: not-inline + BlockContainer at (24,8) content-size 768x255 children: not-inline + BlockContainer <(anonymous)> at (24,8) content-size 768x0 children: inline + TextNode <#text> + BlockContainer at (24,8) content-size 768x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [42,8 14.265625x17] baseline: 13.296875 + "A" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 3, rect: [24,8 18.125x17] baseline: 13.296875 + "1: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (24,25) content-size 768x0 children: inline + TextNode <#text> + BlockContainer at (24,25) content-size 768x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [45,25 9.34375x17] baseline: 13.296875 + "B" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 3, rect: [24,25 20.59375x17] baseline: 13.296875 + "2: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (24,42) content-size 768x0 children: inline + TextNode <#text> + BlockContainer at (24,42) content-size 768x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [45,42 10.3125x17] baseline: 13.296875 + "C" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 3, rect: [24,42 20.875x17] baseline: 13.296875 + "3: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (24,59) content-size 768x0 children: inline + TextNode <#text> + BlockContainer at (24,59) content-size 768x153 children: not-inline + BlockContainer <(anonymous)> at (24,59) content-size 768x17 children: inline + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 2, rect: [24,59 11.53125x17] baseline: 13.296875 + "4:" + TextNode <#text> + TextNode <#text> + BlockContainer at (40,76) content-size 752x136 children: not-inline + BlockContainer <(anonymous)> at (40,76) content-size 752x0 children: inline + TextNode <#text> + BlockContainer at (40,76) content-size 752x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [70,76 11.140625x17] baseline: 13.296875 + "D" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [40,76 30.21875x17] baseline: 13.296875 + "4.1: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (40,93) content-size 752x0 children: inline + TextNode <#text> + BlockContainer at (40,93) content-size 752x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [73,93 11.859375x17] baseline: 13.296875 + "E" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [40,93 32.6875x17] baseline: 13.296875 + "4.2: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (40,110) content-size 752x0 children: inline + TextNode <#text> + BlockContainer at (40,110) content-size 752x68 children: not-inline + BlockContainer <(anonymous)> at (40,110) content-size 752x17 children: inline + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 4, rect: [40,110 24.96875x17] baseline: 13.296875 + "4.3:" + TextNode <#text> + TextNode <#text> + BlockContainer at (56,127) content-size 736x51 children: not-inline + BlockContainer <(anonymous)> at (56,127) content-size 736x0 children: inline + TextNode <#text> + BlockContainer at (56,127) content-size 736x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [100,127 12.546875x17] baseline: 13.296875 + "F" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 7, rect: [56,127 43.65625x17] baseline: 13.296875 + "4.3.1: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (56,144) content-size 736x0 children: inline + TextNode <#text> + BlockContainer at (56,144) content-size 736x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [102,144 13.234375x17] baseline: 13.296875 + "G" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 7, rect: [56,144 46.125x17] baseline: 13.296875 + "4.3.2: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (56,161) content-size 736x0 children: inline + TextNode <#text> + BlockContainer at (56,161) content-size 736x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [102,161 12.234375x17] baseline: 13.296875 + "H" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 7, rect: [56,161 46.40625x17] baseline: 13.296875 + "4.3.3: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (56,178) content-size 736x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (40,178) content-size 752x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (40,178) content-size 752x0 children: inline + TextNode <#text> + BlockContainer at (40,178) content-size 752x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [72,178 4.59375x17] baseline: 13.296875 + "I" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [40,178 31.625x17] baseline: 13.296875 + "4.4: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (40,195) content-size 752x0 children: inline + TextNode <#text> + BlockContainer at (40,195) content-size 752x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [72,195 8.90625x17] baseline: 13.296875 + "J" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 5, rect: [40,195 32.328125x17] baseline: 13.296875 + "4.5: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (40,212) content-size 752x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (24,212) content-size 768x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (24,212) content-size 768x0 children: inline + TextNode <#text> + BlockContainer at (24,212) content-size 768x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [44,212 9.8125x17] baseline: 13.296875 + "K" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 3, rect: [24,212 20.234375x17] baseline: 13.296875 + "5: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (24,229) content-size 768x0 children: inline + TextNode <#text> + BlockContainer at (24,229) content-size 768x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [45,229 10.859375x17] baseline: 13.296875 + "L" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 3, rect: [24,229 20.515625x17] baseline: 13.296875 + "6: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (24,246) content-size 768x0 children: inline + TextNode <#text> + BlockContainer at (24,246) content-size 768x17 children: inline + frag 0 from TextNode start: 0, length: 1, rect: [45,246 11.765625x17] baseline: 13.296875 + "M" + InlineNode <(anonymous)> + frag 0 from TextNode start: 0, length: 3, rect: [24,246 20.5x17] baseline: 13.296875 + "7: " + TextNode <#text> + TextNode <#text> + BlockContainer <(anonymous)> at (24,263) content-size 768x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,263) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x600] + PaintableWithLines (BlockContainer) [8,8 784x255] + PaintableWithLines (BlockContainer

.ol) [8,8 784x255] + PaintableWithLines (BlockContainer(anonymous)) [24,8 768x0] + PaintableWithLines (BlockContainer
.li) [24,8 768x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [24,25 768x0] + PaintableWithLines (BlockContainer
.li) [24,25 768x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [24,42 768x0] + PaintableWithLines (BlockContainer
.li) [24,42 768x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [24,59 768x0] + PaintableWithLines (BlockContainer
.li) [24,59 768x153] + PaintableWithLines (BlockContainer(anonymous)) [24,59 768x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.ol) [24,76 768x136] + PaintableWithLines (BlockContainer(anonymous)) [40,76 752x0] + PaintableWithLines (BlockContainer
.li) [40,76 752x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [40,93 752x0] + PaintableWithLines (BlockContainer
.li) [40,93 752x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [40,110 752x0] + PaintableWithLines (BlockContainer
.li) [40,110 752x68] + PaintableWithLines (BlockContainer(anonymous)) [40,110 752x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.ol) [40,127 752x51] + PaintableWithLines (BlockContainer(anonymous)) [56,127 736x0] + PaintableWithLines (BlockContainer
.li) [56,127 736x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [56,144 736x0] + PaintableWithLines (BlockContainer
.li) [56,144 736x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [56,161 736x0] + PaintableWithLines (BlockContainer
.li) [56,161 736x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [56,178 736x0] + PaintableWithLines (BlockContainer(anonymous)) [40,178 752x0] + PaintableWithLines (BlockContainer(anonymous)) [40,178 752x0] + PaintableWithLines (BlockContainer
.li) [40,178 752x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [40,195 752x0] + PaintableWithLines (BlockContainer
.li) [40,195 752x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [40,212 752x0] + PaintableWithLines (BlockContainer(anonymous)) [24,212 768x0] + PaintableWithLines (BlockContainer(anonymous)) [24,212 768x0] + PaintableWithLines (BlockContainer
.li) [24,212 768x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [24,229 768x0] + PaintableWithLines (BlockContainer
.li) [24,229 768x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [24,246 768x0] + PaintableWithLines (BlockContainer
.li) [24,246 768x17] + InlinePaintable (InlineNode(anonymous)) + TextPaintable (TextNode<#text>) + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer(anonymous)) [24,263 768x0] + PaintableWithLines (BlockContainer(anonymous)) [8,263 784x0] diff --git a/Tests/LibWeb/Layout/input/css-counters/basic.html b/Tests/LibWeb/Layout/input/css-counters/basic.html new file mode 100644 index 0000000000000..c96a460876076 --- /dev/null +++ b/Tests/LibWeb/Layout/input/css-counters/basic.html @@ -0,0 +1,12 @@ +

Never

Gonna

Give

You

Up

Never

Gonna

Let

You

Down

diff --git a/Tests/LibWeb/Layout/input/css-counters/counters-function.html b/Tests/LibWeb/Layout/input/css-counters/counters-function.html new file mode 100644 index 0000000000000..467027d1850ed --- /dev/null +++ b/Tests/LibWeb/Layout/input/css-counters/counters-function.html @@ -0,0 +1,36 @@ + + +
+
A
+
B
+
C
+
+
+
D
+
E
+
+
+
F
+
G
+
H
+
+
+
I
+
J
+
+
+
K
+
L
+
M
+
diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index b4af44601c13d..305aa531c55db 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018-2023, Andreas Kling - * Copyright (c) 2021-2023, Sam Atkins + * Copyright (c) 2021-2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -647,7 +648,7 @@ Optional StyleProperties::clear() const return value_id_to_clear(value->to_identifier()); } -StyleProperties::ContentDataAndQuoteNestingLevel StyleProperties::content(u32 initial_quote_nesting_level) const +StyleProperties::ContentDataAndQuoteNestingLevel StyleProperties::content(DOM::Element& element, u32 initial_quote_nesting_level) const { auto value = property(CSS::PropertyID::Content); auto quotes_data = quotes(); @@ -710,8 +711,10 @@ StyleProperties::ContentDataAndQuoteNestingLevel StyleProperties::content(u32 in dbgln("`{}` is not supported in `content` (yet?)", item->to_string()); break; } + } else if (item->is_counter()) { + builder.append(item->as_counter().resolve(element)); } else { - // TODO: Implement counters, images, and other things. + // TODO: Implement images, and other things. dbgln("`{}` is not supported in `content` (yet?)", item->to_string()); } } @@ -723,8 +726,10 @@ StyleProperties::ContentDataAndQuoteNestingLevel StyleProperties::content(u32 in for (auto const& item : content_style_value.alt_text()->values()) { if (item->is_string()) { alt_text_builder.append(item->as_string().string_value()); + } else if (item->is_counter()) { + alt_text_builder.append(item->as_counter().resolve(element)); } else { - // TODO: Implement counters + dbgln("`{}` is not supported in `content` alt-text (yet?)", item->to_string()); } } content_data.alt_text = MUST(alt_text_builder.to_string()); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 9be8c9a60b4c8..7558842d50318 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -85,7 +85,7 @@ class StyleProperties : public RefCounted { CSS::ContentData content_data; u32 final_quote_nesting_level { 0 }; }; - ContentDataAndQuoteNestingLevel content(u32 initial_quote_nesting_level) const; + ContentDataAndQuoteNestingLevel content(DOM::Element&, u32 initial_quote_nesting_level) const; Optional content_visibility() const; Optional cursor() const; Optional white_space() const; diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp index 358dc9e62c4d0..bf9fd62d1406f 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/CounterStyleValue.cpp @@ -1,13 +1,18 @@ /* + * Copyright (c) 2018-2022, Andreas Kling + * Copyright (c) 2021, Tobias Christiansen * Copyright (c) 2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #include "CounterStyleValue.h" +#include #include #include #include +#include +#include namespace Web::CSS { @@ -24,6 +29,107 @@ CounterStyleValue::CounterStyleValue(CounterFunction function, FlyString counter CounterStyleValue::~CounterStyleValue() = default; +// https://drafts.csswg.org/css-counter-styles-3/#generate-a-counter +static String generate_a_counter_representation(StyleValue const& counter_style, i32 value) +{ + // When asked to generate a counter representation using a particular counter style for a particular + // counter value, follow these steps: + // TODO: 1. If the counter style is unknown, exit this algorithm and instead generate a counter representation + // using the decimal style and the same counter value. + // TODO: 2. If the counter value is outside the range of the counter style, exit this algorithm and instead + // generate a counter representation using the counter style’s fallback style and the same counter value. + // TODO: 3. Using the counter value and the counter algorithm for the counter style, generate an initial + // representation for the counter value. + // If the counter value is negative and the counter style uses a negative sign, instead generate an + // initial representation using the absolute value of the counter value. + // TODO: 4. Prepend symbols to the representation as specified in the pad descriptor. + // TODO: 5. If the counter value is negative and the counter style uses a negative sign, wrap the representation + // in the counter style’s negative sign as specified in the negative descriptor. + // TODO: 6. Return the representation. + + // FIXME: Below is an ad-hoc implementation until we support @counter-style. + // It's based largely on the ListItemMarkerBox code, with minimal adjustments. + if (counter_style.is_custom_ident()) { + auto counter_style_name = counter_style.as_custom_ident().custom_ident(); + auto identifier = value_id_from_string(counter_style_name); + if (identifier.has_value()) { + auto list_style_type = value_id_to_list_style_type(*identifier); + if (list_style_type.has_value()) { + switch (*list_style_type) { + case ListStyleType::Square: + return "▪"_string; + case ListStyleType::Circle: + return "◦"_string; + case ListStyleType::Disc: + return "•"_string; + case ListStyleType::DisclosureClosed: + return "▸"_string; + case ListStyleType::DisclosureOpen: + return "▾"_string; + case ListStyleType::Decimal: + return MUST(String::formatted("{}", value)); + case ListStyleType::DecimalLeadingZero: + // This is weird, but in accordance to spec. + if (value < 10) + return MUST(String::formatted("0{}", value)); + return MUST(String::formatted("{}", value)); + case ListStyleType::LowerAlpha: + case ListStyleType::LowerLatin: + return MUST(String::from_byte_string(ByteString::bijective_base_from(value - 1).to_lowercase())); + case ListStyleType::UpperAlpha: + case ListStyleType::UpperLatin: + return MUST(String::from_byte_string(ByteString::bijective_base_from(value - 1))); + case ListStyleType::LowerRoman: + return MUST(String::from_byte_string(ByteString::roman_number_from(value).to_lowercase())); + case ListStyleType::UpperRoman: + return MUST(String::from_byte_string(ByteString::roman_number_from(value))); + default: + break; + } + } + } + } + // FIXME: Handle `symbols()` function for counter_style. + + dbgln("FIXME: Unsupported counter style '{}'", counter_style.to_string()); + return MUST(String::formatted("{}", value)); +} + +String CounterStyleValue::resolve(DOM::Element& element) const +{ + // "If no counter named exists on an element where counter() or counters() is used, + // one is first instantiated with a starting value of 0." + auto& counters_set = element.ensure_counters_set(); + if (!counters_set.last_counter_with_name(m_properties.counter_name).has_value()) + counters_set.instantiate_a_counter(m_properties.counter_name, element.unique_id(), false, 0); + + // counter( , ? ) + // "Represents the value of the innermost counter in the element’s CSS counters set named + // using the counter style named ." + if (m_properties.function == CounterFunction::Counter) { + // NOTE: This should always be present because of the handling of a missing counter above. + auto& counter = counters_set.last_counter_with_name(m_properties.counter_name).value(); + return generate_a_counter_representation(m_properties.counter_style, counter.value.value_or(0).value()); + } + + // counters( , , ? ) + // "Represents the values of all the counters in the element’s CSS counters set named + // using the counter style named , sorted in outermost-first to innermost-last order + // and joined by the specified ." + // NOTE: The way counters sets are inherited, this should be the order they appear in the counters set. + StringBuilder stb; + for (auto const& counter : counters_set.counters()) { + if (counter.name != m_properties.counter_name) + continue; + + auto counter_string = generate_a_counter_representation(m_properties.counter_style, counter.value.value_or(0).value()); + if (!stb.is_empty()) + stb.append(m_properties.join_string); + stb.append(counter_string); + } + return stb.to_string_without_validation(); +} + // https://drafts.csswg.org/cssom-1/#ref-for-typedef-counter String CounterStyleValue::to_string() const { diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp index 61e4f566fc4b4..98c7d3f88d415 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -198,7 +198,7 @@ void TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, CSS::Se return; auto initial_quote_nesting_level = m_quote_nesting_level; - auto [pseudo_element_content, final_quote_nesting_level] = pseudo_element_style->content(initial_quote_nesting_level); + auto [pseudo_element_content, final_quote_nesting_level] = pseudo_element_style->content(element, initial_quote_nesting_level); m_quote_nesting_level = final_quote_nesting_level; auto pseudo_element_display = pseudo_element_style->display(); // ::before and ::after only exist if they have content. `content: normal` computes to `none` for them.