mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:07:35 +00:00
LibWeb: Track quote-nesting level while building the layout tree
This makes multiple levels of quote actually use different quotation marks, instead of always the first available pair of them. Each Layout::Node remembers what the quote-nesting level was before its content was evaluated, so that we can re-use this number in `apply_style()`. This is a bit hacky, since we end up converting the `content` value into a string twice. `StyleProperties::content()` now takes an initial quote-nesting level, and returns the final level after that content.
This commit is contained in:
parent
493dd5d93c
commit
9e99368694
8 changed files with 372 additions and 14 deletions
313
Tests/LibWeb/Layout/expected/css-quotes-nesting.txt
Normal file
313
Tests/LibWeb/Layout/expected/css-quotes-nesting.txt
Normal file
|
@ -0,0 +1,313 @@
|
||||||
|
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||||
|
BlockContainer <html> at (0,0) content-size 800x68.40625 [BFC] children: not-inline
|
||||||
|
BlockContainer <body> at (8,8) content-size 784x52.40625 children: not-inline
|
||||||
|
BlockContainer <div.a> at (8,8) content-size 784x17.46875 children: inline
|
||||||
|
line 0 width: 72.140625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||||
|
frag 0 from TextNode start: 0, length: 1, rect: [8,8 9.34375x17.46875]
|
||||||
|
"a"
|
||||||
|
frag 1 from TextNode start: 0, length: 1, rect: [17,8 9.46875x17.46875]
|
||||||
|
"b"
|
||||||
|
frag 2 from TextNode start: 0, length: 1, rect: [27,8 8.890625x17.46875]
|
||||||
|
"c"
|
||||||
|
frag 3 from TextNode start: 0, length: 1, rect: [36,8 7.859375x17.46875]
|
||||||
|
"d"
|
||||||
|
frag 4 from TextNode start: 0, length: 1, rect: [44,8 8.71875x17.46875]
|
||||||
|
"e"
|
||||||
|
frag 5 from TextNode start: 0, length: 1, rect: [52,8 6.4375x17.46875]
|
||||||
|
"f"
|
||||||
|
frag 6 from TextNode start: 0, length: 1, rect: [59,8 7.5625x17.46875]
|
||||||
|
"g"
|
||||||
|
frag 7 from TextNode start: 0, length: 1, rect: [66,8 9.296875x17.46875]
|
||||||
|
"h"
|
||||||
|
frag 8 from TextNode start: 0, length: 1, rect: [76,8 4.5625x17.46875]
|
||||||
|
"i"
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
BlockContainer <(anonymous)> at (8,25.46875) content-size 784x0 children: inline
|
||||||
|
TextNode <#text>
|
||||||
|
BlockContainer <div.b> at (8,25.46875) content-size 784x17.46875 children: inline
|
||||||
|
line 0 width: 130.578125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||||
|
frag 0 from TextNode start: 0, length: 3, rect: [8,25.46875 5.84375x17.46875]
|
||||||
|
"“"
|
||||||
|
frag 1 from TextNode start: 0, length: 1, rect: [14,25.46875 9.34375x17.46875]
|
||||||
|
"a"
|
||||||
|
frag 2 from TextNode start: 0, length: 3, rect: [23,25.46875 5.84375x17.46875]
|
||||||
|
"‘"
|
||||||
|
frag 3 from TextNode start: 0, length: 1, rect: [29,25.46875 9.46875x17.46875]
|
||||||
|
"b"
|
||||||
|
frag 4 from TextNode start: 0, length: 3, rect: [39,25.46875 5.84375x17.46875]
|
||||||
|
"‘"
|
||||||
|
frag 5 from TextNode start: 0, length: 1, rect: [44,25.46875 8.890625x17.46875]
|
||||||
|
"c"
|
||||||
|
frag 6 from TextNode start: 0, length: 3, rect: [53,25.46875 5.84375x17.46875]
|
||||||
|
"‘"
|
||||||
|
frag 7 from TextNode start: 0, length: 1, rect: [59,25.46875 7.859375x17.46875]
|
||||||
|
"d"
|
||||||
|
frag 8 from TextNode start: 0, length: 3, rect: [67,25.46875 5.84375x17.46875]
|
||||||
|
"‘"
|
||||||
|
frag 9 from TextNode start: 0, length: 1, rect: [73,25.46875 8.71875x17.46875]
|
||||||
|
"e"
|
||||||
|
frag 10 from TextNode start: 0, length: 3, rect: [82,25.46875 5.84375x17.46875]
|
||||||
|
"’"
|
||||||
|
frag 11 from TextNode start: 0, length: 1, rect: [87,25.46875 6.4375x17.46875]
|
||||||
|
"f"
|
||||||
|
frag 12 from TextNode start: 0, length: 3, rect: [94,25.46875 5.84375x17.46875]
|
||||||
|
"’"
|
||||||
|
frag 13 from TextNode start: 0, length: 1, rect: [100,25.46875 7.5625x17.46875]
|
||||||
|
"g"
|
||||||
|
frag 14 from TextNode start: 0, length: 3, rect: [107,25.46875 5.84375x17.46875]
|
||||||
|
"’"
|
||||||
|
frag 15 from TextNode start: 0, length: 1, rect: [113,25.46875 9.296875x17.46875]
|
||||||
|
"h"
|
||||||
|
frag 16 from TextNode start: 0, length: 3, rect: [122,25.46875 5.84375x17.46875]
|
||||||
|
"’"
|
||||||
|
frag 17 from TextNode start: 0, length: 1, rect: [128,25.46875 4.5625x17.46875]
|
||||||
|
"i"
|
||||||
|
frag 18 from TextNode start: 0, length: 3, rect: [133,25.46875 5.84375x17.46875]
|
||||||
|
"”"
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
BlockContainer <(anonymous)> at (8,42.9375) content-size 784x0 children: inline
|
||||||
|
TextNode <#text>
|
||||||
|
BlockContainer <div.c> at (8,42.9375) content-size 784x17.46875 children: inline
|
||||||
|
line 0 width: 140.234375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||||
|
frag 0 from TextNode start: 0, length: 1, rect: [8,42.9375 5.484375x17.46875]
|
||||||
|
"("
|
||||||
|
frag 1 from TextNode start: 0, length: 1, rect: [13,42.9375 9.34375x17.46875]
|
||||||
|
"a"
|
||||||
|
frag 2 from TextNode start: 0, length: 1, rect: [23,42.9375 7.625x17.46875]
|
||||||
|
"{"
|
||||||
|
frag 3 from TextNode start: 0, length: 1, rect: [30,42.9375 9.46875x17.46875]
|
||||||
|
"b"
|
||||||
|
frag 4 from TextNode start: 0, length: 1, rect: [40,42.9375 6.953125x17.46875]
|
||||||
|
"["
|
||||||
|
frag 5 from TextNode start: 0, length: 1, rect: [47,42.9375 8.890625x17.46875]
|
||||||
|
"c"
|
||||||
|
frag 6 from TextNode start: 0, length: 1, rect: [56,42.9375 6.953125x17.46875]
|
||||||
|
"["
|
||||||
|
frag 7 from TextNode start: 0, length: 1, rect: [63,42.9375 7.859375x17.46875]
|
||||||
|
"d"
|
||||||
|
frag 8 from TextNode start: 0, length: 1, rect: [71,42.9375 6.953125x17.46875]
|
||||||
|
"["
|
||||||
|
frag 9 from TextNode start: 0, length: 1, rect: [78,42.9375 8.71875x17.46875]
|
||||||
|
"e"
|
||||||
|
frag 10 from TextNode start: 0, length: 1, rect: [86,42.9375 7.21875x17.46875]
|
||||||
|
"]"
|
||||||
|
frag 11 from TextNode start: 0, length: 1, rect: [93,42.9375 6.4375x17.46875]
|
||||||
|
"f"
|
||||||
|
frag 12 from TextNode start: 0, length: 1, rect: [100,42.9375 7.21875x17.46875]
|
||||||
|
"]"
|
||||||
|
frag 13 from TextNode start: 0, length: 1, rect: [107,42.9375 7.5625x17.46875]
|
||||||
|
"g"
|
||||||
|
frag 14 from TextNode start: 0, length: 1, rect: [115,42.9375 7.21875x17.46875]
|
||||||
|
"]"
|
||||||
|
frag 15 from TextNode start: 0, length: 1, rect: [122,42.9375 9.296875x17.46875]
|
||||||
|
"h"
|
||||||
|
frag 16 from TextNode start: 0, length: 1, rect: [131,42.9375 7.65625x17.46875]
|
||||||
|
"}"
|
||||||
|
frag 17 from TextNode start: 0, length: 1, rect: [139,42.9375 4.5625x17.46875]
|
||||||
|
"i"
|
||||||
|
frag 18 from TextNode start: 0, length: 1, rect: [143,42.9375 4.8125x17.46875]
|
||||||
|
")"
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <span>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
InlineNode <(anonymous)>
|
||||||
|
TextNode <#text>
|
||||||
|
BlockContainer <(anonymous)> at (8,60.40625) content-size 784x0 children: inline
|
||||||
|
TextNode <#text>
|
||||||
|
|
||||||
|
ViewportPaintable (Viewport<#document>) [0,0 800x600]
|
||||||
|
PaintableWithLines (BlockContainer<HTML>) [0,0 800x68.40625]
|
||||||
|
PaintableWithLines (BlockContainer<BODY>) [8,8 784x52.40625]
|
||||||
|
PaintableWithLines (BlockContainer<DIV>.a) [8,8 784x17.46875]
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
PaintableWithLines (BlockContainer(anonymous)) [8,25.46875 784x0]
|
||||||
|
PaintableWithLines (BlockContainer<DIV>.b) [8,25.46875 784x17.46875]
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
PaintableWithLines (BlockContainer(anonymous)) [8,42.9375 784x0]
|
||||||
|
PaintableWithLines (BlockContainer<DIV>.c) [8,42.9375 784x17.46875]
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode<SPAN>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
InlinePaintable (InlineNode(anonymous))
|
||||||
|
TextPaintable (TextNode<#text>)
|
||||||
|
PaintableWithLines (BlockContainer(anonymous)) [8,60.40625 784x0]
|
21
Tests/LibWeb/Layout/input/css-quotes-nesting.html
Normal file
21
Tests/LibWeb/Layout/input/css-quotes-nesting.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<!doctype html>
|
||||||
|
<style>
|
||||||
|
span::before {
|
||||||
|
content: open-quote;
|
||||||
|
}
|
||||||
|
span::after {
|
||||||
|
content: close-quote;
|
||||||
|
}
|
||||||
|
.a {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
.b {
|
||||||
|
quotes: auto;
|
||||||
|
}
|
||||||
|
.c {
|
||||||
|
quotes: "(" ")" "{" "}" "[" "]";
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="a"><span>a<span>b<span>c<span>d<span>e</span>f</span>g</span>h</span>i</span></div>
|
||||||
|
<div class="b"><span>a<span>b<span>c<span>d<span>e</span>f</span>g</span>h</span>i</span></div>
|
||||||
|
<div class="c"><span>a<span>b<span>c<span>d<span>e</span>f</span>g</span>h</span>i</span></div>
|
|
@ -646,11 +646,13 @@ Optional<CSS::Clear> StyleProperties::clear() const
|
||||||
return value_id_to_clear(value->to_identifier());
|
return value_id_to_clear(value->to_identifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
CSS::ContentData StyleProperties::content() const
|
StyleProperties::ContentDataAndQuoteNestingLevel StyleProperties::content(u32 initial_quote_nesting_level) const
|
||||||
{
|
{
|
||||||
auto value = property(CSS::PropertyID::Content);
|
auto value = property(CSS::PropertyID::Content);
|
||||||
auto quotes_data = quotes();
|
auto quotes_data = quotes();
|
||||||
|
|
||||||
|
auto quote_nesting_level = initial_quote_nesting_level;
|
||||||
|
|
||||||
auto get_quote_string = [&](bool open, auto depth) {
|
auto get_quote_string = [&](bool open, auto depth) {
|
||||||
switch (quotes_data.type) {
|
switch (quotes_data.type) {
|
||||||
case QuotesData::Type::None:
|
case QuotesData::Type::None:
|
||||||
|
@ -684,18 +686,24 @@ CSS::ContentData StyleProperties::content() const
|
||||||
} else if (item->is_identifier()) {
|
} else if (item->is_identifier()) {
|
||||||
switch (item->to_identifier()) {
|
switch (item->to_identifier()) {
|
||||||
case ValueID::OpenQuote:
|
case ValueID::OpenQuote:
|
||||||
// FIXME: Track nesting level and increment it here.
|
builder.append(get_quote_string(true, quote_nesting_level++));
|
||||||
builder.append(get_quote_string(true, 1));
|
|
||||||
break;
|
break;
|
||||||
case ValueID::CloseQuote:
|
case ValueID::CloseQuote:
|
||||||
// FIXME: Track nesting level and decrement it here.
|
// A 'close-quote' or 'no-close-quote' that would make the depth negative is in error and is ignored
|
||||||
builder.append(get_quote_string(false, 1));
|
// (at rendering time): the depth stays at 0 and no quote mark is rendered (although the rest of the
|
||||||
|
// 'content' property's value is still inserted).
|
||||||
|
// - https://www.w3.org/TR/CSS21/generate.html#quotes-insert
|
||||||
|
// (This is missing from the CONTENT-3 spec.)
|
||||||
|
if (quote_nesting_level > 0)
|
||||||
|
builder.append(get_quote_string(false, --quote_nesting_level));
|
||||||
break;
|
break;
|
||||||
case ValueID::NoOpenQuote:
|
case ValueID::NoOpenQuote:
|
||||||
// FIXME: Track nesting level and increment it here.
|
quote_nesting_level++;
|
||||||
break;
|
break;
|
||||||
case ValueID::NoCloseQuote:
|
case ValueID::NoCloseQuote:
|
||||||
// FIXME: Track nesting level and decrement it here.
|
// NOTE: See CloseQuote
|
||||||
|
if (quote_nesting_level > 0)
|
||||||
|
quote_nesting_level--;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dbgln("`{}` is not supported in `content` (yet?)", item->to_string());
|
dbgln("`{}` is not supported in `content` (yet?)", item->to_string());
|
||||||
|
@ -721,19 +729,19 @@ CSS::ContentData StyleProperties::content() const
|
||||||
content_data.alt_text = MUST(alt_text_builder.to_string());
|
content_data.alt_text = MUST(alt_text_builder.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
return content_data;
|
return { content_data, quote_nesting_level };
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (value->to_identifier()) {
|
switch (value->to_identifier()) {
|
||||||
case ValueID::None:
|
case ValueID::None:
|
||||||
return { ContentData::Type::None };
|
return { { ContentData::Type::None }, quote_nesting_level };
|
||||||
case ValueID::Normal:
|
case ValueID::Normal:
|
||||||
return { ContentData::Type::Normal };
|
return { { ContentData::Type::Normal }, quote_nesting_level };
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSS::ContentData {};
|
return { {}, quote_nesting_level };
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<CSS::Cursor> StyleProperties::cursor() const
|
Optional<CSS::Cursor> StyleProperties::cursor() const
|
||||||
|
|
|
@ -64,7 +64,11 @@ public:
|
||||||
CSS::Display display() const;
|
CSS::Display display() const;
|
||||||
Optional<CSS::Float> float_() const;
|
Optional<CSS::Float> float_() const;
|
||||||
Optional<CSS::Clear> clear() const;
|
Optional<CSS::Clear> clear() const;
|
||||||
CSS::ContentData content() const;
|
struct ContentDataAndQuoteNestingLevel {
|
||||||
|
CSS::ContentData content_data;
|
||||||
|
u32 final_quote_nesting_level { 0 };
|
||||||
|
};
|
||||||
|
ContentDataAndQuoteNestingLevel content(u32 initial_quote_nesting_level) const;
|
||||||
Optional<CSS::Cursor> cursor() const;
|
Optional<CSS::Cursor> cursor() const;
|
||||||
Optional<CSS::WhiteSpace> white_space() const;
|
Optional<CSS::WhiteSpace> white_space() const;
|
||||||
Optional<CSS::LineStyle> line_style(CSS::PropertyID) const;
|
Optional<CSS::LineStyle> line_style(CSS::PropertyID) const;
|
||||||
|
|
|
@ -743,7 +743,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
|
||||||
if (auto outline_width = computed_style.property(CSS::PropertyID::OutlineWidth); outline_width->is_length())
|
if (auto outline_width = computed_style.property(CSS::PropertyID::OutlineWidth); outline_width->is_length())
|
||||||
computed_values.set_outline_width(outline_width->as_length().length());
|
computed_values.set_outline_width(outline_width->as_length().length());
|
||||||
|
|
||||||
computed_values.set_content(computed_style.content());
|
// FIXME: Stop generating the content twice. (First time is in TreeBuilder.)
|
||||||
|
computed_values.set_content(computed_style.content(initial_quote_nesting_level()).content_data);
|
||||||
computed_values.set_grid_auto_columns(computed_style.grid_auto_columns());
|
computed_values.set_grid_auto_columns(computed_style.grid_auto_columns());
|
||||||
computed_values.set_grid_auto_rows(computed_style.grid_auto_rows());
|
computed_values.set_grid_auto_rows(computed_style.grid_auto_rows());
|
||||||
computed_values.set_grid_template_columns(computed_style.grid_template_columns());
|
computed_values.set_grid_template_columns(computed_style.grid_template_columns());
|
||||||
|
|
|
@ -175,6 +175,9 @@ public:
|
||||||
SelectionState selection_state() const { return m_selection_state; }
|
SelectionState selection_state() const { return m_selection_state; }
|
||||||
void set_selection_state(SelectionState state) { m_selection_state = state; }
|
void set_selection_state(SelectionState state) { m_selection_state = state; }
|
||||||
|
|
||||||
|
u32 initial_quote_nesting_level() const { return m_initial_quote_nesting_level; }
|
||||||
|
void set_initial_quote_nesting_level(u32 value) { m_initial_quote_nesting_level = value; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Node(DOM::Document&, DOM::Node*);
|
Node(DOM::Document&, DOM::Node*);
|
||||||
|
|
||||||
|
@ -199,6 +202,8 @@ private:
|
||||||
bool m_is_grid_item { false };
|
bool m_is_grid_item { false };
|
||||||
|
|
||||||
GeneratedFor m_generated_for { GeneratedFor::NotGenerated };
|
GeneratedFor m_generated_for { GeneratedFor::NotGenerated };
|
||||||
|
|
||||||
|
u32 m_initial_quote_nesting_level { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class NodeWithStyle : public Node {
|
class NodeWithStyle : public Node {
|
||||||
|
|
|
@ -181,7 +181,9 @@ ErrorOr<void> TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element
|
||||||
if (!pseudo_element_style)
|
if (!pseudo_element_style)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto pseudo_element_content = pseudo_element_style->content();
|
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);
|
||||||
|
m_quote_nesting_level = final_quote_nesting_level;
|
||||||
auto pseudo_element_display = pseudo_element_style->display();
|
auto pseudo_element_display = pseudo_element_style->display();
|
||||||
// ::before and ::after only exist if they have content. `content: normal` computes to `none` for them.
|
// ::before and ::after only exist if they have content. `content: normal` computes to `none` for them.
|
||||||
// We also don't create them if they are `display: none`.
|
// We also don't create them if they are `display: none`.
|
||||||
|
@ -204,6 +206,7 @@ ErrorOr<void> TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo_element_node->set_generated_for(generated_for, element);
|
pseudo_element_node->set_generated_for(generated_for, element);
|
||||||
|
pseudo_element_node->set_initial_quote_nesting_level(initial_quote_nesting_level);
|
||||||
|
|
||||||
// FIXME: Handle images, and multiple values
|
// FIXME: Handle images, and multiple values
|
||||||
if (pseudo_element_content.type == CSS::ContentData::Type::String) {
|
if (pseudo_element_content.type == CSS::ContentData::Type::String) {
|
||||||
|
@ -452,6 +455,7 @@ JS::GCPtr<Layout::Node> TreeBuilder::build(DOM::Node& dom_node)
|
||||||
VERIFY(dom_node.is_document());
|
VERIFY(dom_node.is_document());
|
||||||
|
|
||||||
Context context;
|
Context context;
|
||||||
|
m_quote_nesting_level = 0;
|
||||||
MUST(create_layout_tree(dom_node, context)); // FIXME propagate errors
|
MUST(create_layout_tree(dom_node, context)); // FIXME propagate errors
|
||||||
|
|
||||||
if (auto* root = dom_node.document().layout_node())
|
if (auto* root = dom_node.document().layout_node())
|
||||||
|
|
|
@ -51,6 +51,8 @@ private:
|
||||||
|
|
||||||
JS::GCPtr<Layout::Node> m_layout_root;
|
JS::GCPtr<Layout::Node> m_layout_root;
|
||||||
Vector<JS::NonnullGCPtr<Layout::NodeWithStyle>> m_ancestor_stack;
|
Vector<JS::NonnullGCPtr<Layout::NodeWithStyle>> m_ancestor_stack;
|
||||||
|
|
||||||
|
u32 m_quote_nesting_level { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue