Last: LibWeb: Add counter() and counters() functions to content property

These let you format counters' current values as strings for use in
generated content.
This commit is contained in:
Sam Atkins 2024-07-18 20:29:02 +01:00
parent 576a431408
commit 898e3bd898
Notes: github-actions[bot] 2024-07-26 10:05:28 +00:00
8 changed files with 553 additions and 6 deletions

View file

@ -0,0 +1,134 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,16) content-size 784x314 children: not-inline
BlockContainer <div> at (8,16) content-size 784x149 children: not-inline
BlockContainer <p> 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 <p> 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 <p> 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 <p> 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 <p> 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 <div> at (8,181) content-size 784x149 children: not-inline
BlockContainer <p> 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 <p> 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 <p> 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 <p> 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 <p> 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<HTML>) [0,0 800x600]
PaintableWithLines (BlockContainer<BODY>) [8,16 784x314] overflow: [8,16 784x330]
PaintableWithLines (BlockContainer<DIV>) [8,16 784x149]
PaintableWithLines (BlockContainer<P>) [8,16 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,49 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,82 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,115 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,148 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>) [8,181 784x149]
PaintableWithLines (BlockContainer<P>) [8,181 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,214 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,247 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,280 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<P>) [8,313 784x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,346 784x0]

View file

@ -0,0 +1,254 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x255 children: not-inline
BlockContainer <div.ol> at (24,8) content-size 768x255 children: not-inline
BlockContainer <(anonymous)> at (24,8) content-size 768x0 children: inline
TextNode <#text>
BlockContainer <div.li> 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 <div.li> 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 <div.li> 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 <div.li> 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 <div.ol> at (40,76) content-size 752x136 children: not-inline
BlockContainer <(anonymous)> at (40,76) content-size 752x0 children: inline
TextNode <#text>
BlockContainer <div.li> 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 <div.li> 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 <div.li> 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 <div.ol> at (56,127) content-size 736x51 children: not-inline
BlockContainer <(anonymous)> at (56,127) content-size 736x0 children: inline
TextNode <#text>
BlockContainer <div.li> 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 <div.li> 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 <div.li> 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 <div.li> 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 <div.li> 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 <div.li> 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 <div.li> 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 <div.li> 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<HTML>) [0,0 800x600]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x255]
PaintableWithLines (BlockContainer<DIV>.ol) [8,8 784x255]
PaintableWithLines (BlockContainer(anonymous)) [24,8 768x0]
PaintableWithLines (BlockContainer<DIV>.li) [24,8 768x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [24,25 768x0]
PaintableWithLines (BlockContainer<DIV>.li) [24,25 768x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [24,42 768x0]
PaintableWithLines (BlockContainer<DIV>.li) [24,42 768x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [24,59 768x0]
PaintableWithLines (BlockContainer<DIV>.li) [24,59 768x153]
PaintableWithLines (BlockContainer(anonymous)) [24,59 768x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.ol) [24,76 768x136]
PaintableWithLines (BlockContainer(anonymous)) [40,76 752x0]
PaintableWithLines (BlockContainer<DIV>.li) [40,76 752x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [40,93 752x0]
PaintableWithLines (BlockContainer<DIV>.li) [40,93 752x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [40,110 752x0]
PaintableWithLines (BlockContainer<DIV>.li) [40,110 752x68]
PaintableWithLines (BlockContainer(anonymous)) [40,110 752x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.ol) [40,127 752x51]
PaintableWithLines (BlockContainer(anonymous)) [56,127 736x0]
PaintableWithLines (BlockContainer<DIV>.li) [56,127 736x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [56,144 736x0]
PaintableWithLines (BlockContainer<DIV>.li) [56,144 736x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [56,161 736x0]
PaintableWithLines (BlockContainer<DIV>.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<DIV>.li) [40,178 752x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [40,195 752x0]
PaintableWithLines (BlockContainer<DIV>.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<DIV>.li) [24,212 768x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [24,229 768x0]
PaintableWithLines (BlockContainer<DIV>.li) [24,229 768x17]
InlinePaintable (InlineNode(anonymous))
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [24,246 768x0]
PaintableWithLines (BlockContainer<DIV>.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]

View file

@ -0,0 +1,12 @@
<style>
div {
counter-increment: line;
counter-reset: word;
}
p {
counter-increment: word;
}
p::before {
content: counter(line) "." counter(word) ": ";
}
</style><div><p>Never<p>Gonna<p>Give<p>You<p>Up</div><div><p>Never<p>Gonna<p>Let<p>You<p>Down</div>

View file

@ -0,0 +1,36 @@
<style>
div.ol {
counter-reset: index;
padding-left: 1em;
}
div.li {
counter-increment: index;
}
div.li::before {
content: counters(index, ".") ": ";
}
</style>
<div class="ol">
<div class="li">A</div>
<div class="li">B</div>
<div class="li">C</div>
<div class="li">
<div class="ol">
<div class="li">D</div>
<div class="li">E</div>
<div class="li">
<div class="ol">
<div class="li">F</div>
<div class="li">G</div>
<div class="li">H</div>
</div>
</div>
<div class="li">I</div>
<div class="li">J</div>
</div>
</div>
<div class="li">K</div>
<div class="li">L</div>
<div class="li">M</div>
</div>

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2024, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -12,6 +12,7 @@
#include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
#include <LibWeb/CSS/StyleValues/CounterDefinitionsStyleValue.h>
#include <LibWeb/CSS/StyleValues/CounterStyleValue.h>
#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridAutoFlowStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
@ -647,7 +648,7 @@ Optional<CSS::Clear> 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());

View file

@ -85,7 +85,7 @@ public:
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<CSS::ContentVisibility> content_visibility() const;
Optional<CSS::Cursor> cursor() const;
Optional<CSS::WhiteSpace> white_space() const;

View file

@ -1,13 +1,18 @@
/*
* Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2024, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "CounterStyleValue.h"
#include <LibWeb/CSS/Enums.h>
#include <LibWeb/CSS/Serialize.h>
#include <LibWeb/CSS/StyleValues/CustomIdentStyleValue.h>
#include <LibWeb/CSS/StyleValues/StringStyleValue.h>
#include <LibWeb/CSS/ValueID.h>
#include <LibWeb/DOM/Element.h>
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 styles 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 styles 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 <counter-name> 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( <counter-name>, <counter-style>? )
// "Represents the value of the innermost counter in the elements CSS counters set named <counter-name>
// using the counter style named <counter-style>."
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( <counter-name>, <string>, <counter-style>? )
// "Represents the values of all the counters in the elements CSS counters set named <counter-name>
// using the counter style named <counter-style>, sorted in outermost-first to innermost-last order
// and joined by the specified <string>."
// 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
{

View file

@ -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.