From 940d9b98ae72a549ebd3cbfdf8f2f04345a53246 Mon Sep 17 00:00:00 2001 From: Andi Gallo Date: Wed, 7 Jun 2023 02:10:55 +0000 Subject: [PATCH] LibWeb: Add support for table caption Adds layout support and the CSS caption-side property. --- Tests/LibWeb/Layout/expected/table/basic.txt | 31 +++--- .../Layout/expected/table/bottom-caption.txt | 69 +++++++++++++ .../table/long-caption-increases-width.txt | 96 +++++++++++++++++++ .../Layout/input/table/bottom-caption.html | 40 ++++++++ .../table/long-caption-increases-width.html | 47 +++++++++ .../Libraries/LibWeb/CSS/ComputedValues.h | 4 + Userland/Libraries/LibWeb/CSS/Enums.json | 4 + Userland/Libraries/LibWeb/CSS/Properties.json | 5 +- .../CSS/ResolvedCSSStyleDeclaration.cpp | 3 + .../Libraries/LibWeb/CSS/StyleProperties.cpp | 6 ++ .../Libraries/LibWeb/CSS/StyleProperties.h | 1 + .../LibWeb/Layout/BlockFormattingContext.h | 3 +- Userland/Libraries/LibWeb/Layout/Node.cpp | 4 + .../LibWeb/Layout/TableFormattingContext.cpp | 59 +++++++++++- .../LibWeb/Layout/TableFormattingContext.h | 2 + 15 files changed, 353 insertions(+), 21 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/table/bottom-caption.txt create mode 100644 Tests/LibWeb/Layout/expected/table/long-caption-increases-width.txt create mode 100644 Tests/LibWeb/Layout/input/table/bottom-caption.html create mode 100644 Tests/LibWeb/Layout/input/table/long-caption-increases-width.html diff --git a/Tests/LibWeb/Layout/expected/table/basic.txt b/Tests/LibWeb/Layout/expected/table/basic.txt index 22af3d09f0..81a51724c4 100644 --- a/Tests/LibWeb/Layout/expected/table/basic.txt +++ b/Tests/LibWeb/Layout/expected/table/basic.txt @@ -1,28 +1,31 @@ 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 784x58.40625 children: not-inline + BlockContainer at (8,8) content-size 784x75.875 children: not-inline TableWrapper <(anonymous)> at (8,8) content-size 0x0 [BFC] children: not-inline Box at (8,8) content-size 0x0 table-box [TFC] children: not-inline BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline TextNode <#text> TextNode <#text> - TableWrapper <(anonymous)> at (8,8) content-size 95.171875x58.40625 [BFC] children: not-inline - Box at (8,8) content-size 95.171875x58.40625 table-box [TFC] children: not-inline + TableWrapper <(anonymous)> at (8,8) content-size 95.171875x75.875 [BFC] children: not-inline + Box at (8,25.46875) content-size 95.171875x58.40625 table-box [TFC] children: not-inline BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - BlockContainer (not painted) [BFC] children: inline + BlockContainer at (8,8) content-size 82.734375x17.46875 [BFC] children: inline + line 0 width: 82.734375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 1, length: 9, rect: [14,8 82.734375x17.46875] + "A Caption" TextNode <#text> BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> Box at (8,8) content-size 95.171875x19.46875 table-header-group children: not-inline BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - Box at (8,8) content-size 95.171875x19.46875 table-row children: not-inline + Box at (8,25.46875) content-size 95.171875x19.46875 table-row children: not-inline BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - BlockContainer at (9,9) content-size 93.171875x17.46875 table-cell [BFC] children: inline + BlockContainer at (9,26.46875) content-size 93.171875x17.46875 table-cell [BFC] children: inline line 0 width: 73.65625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 9, rect: [9,9 73.65625x17.46875] + frag 0 from TextNode start: 0, length: 9, rect: [9,26.46875 73.65625x17.46875] "Head Cell" TextNode <#text> BlockContainer <(anonymous)> (not painted) children: inline @@ -34,12 +37,12 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline Box at (8,27.46875) content-size 95.171875x19.46875 table-row-group children: not-inline BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - Box at (8,27.46875) content-size 95.171875x19.46875 table-row children: not-inline + Box at (8,44.9375) content-size 95.171875x19.46875 table-row children: not-inline BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - BlockContainer at (9,28.46875) content-size 93.171875x17.46875 table-cell [BFC] children: inline + BlockContainer at (9,45.9375) content-size 93.171875x17.46875 table-cell [BFC] children: inline line 0 width: 70.234375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 9, rect: [9,28.46875 70.234375x17.46875] + frag 0 from TextNode start: 0, length: 9, rect: [9,45.9375 70.234375x17.46875] "Body Cell" TextNode <#text> BlockContainer <(anonymous)> (not painted) children: inline @@ -51,12 +54,12 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline Box at (8,46.9375) content-size 95.171875x19.46875 table-footer-group children: not-inline BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - Box at (8,46.9375) content-size 95.171875x19.46875 table-row children: not-inline + Box at (8,64.40625) content-size 95.171875x19.46875 table-row children: not-inline BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - BlockContainer at (9,47.9375) content-size 93.171875x17.46875 table-cell [BFC] children: inline + BlockContainer at (9,65.40625) content-size 93.171875x17.46875 table-cell [BFC] children: inline line 0 width: 93.171875, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 11, rect: [9,47.9375 93.171875x17.46875] + frag 0 from TextNode start: 0, length: 11, rect: [9,65.40625 93.171875x17.46875] "Footer Cell" TextNode <#text> BlockContainer <(anonymous)> (not painted) children: inline @@ -65,5 +68,5 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline TextNode <#text> BlockContainer <(anonymous)> (not painted) children: inline TextNode <#text> - BlockContainer <(anonymous)> at (8,66.40625) content-size 784x0 children: inline + BlockContainer <(anonymous)> at (8,83.875) content-size 784x0 children: inline TextNode <#text> diff --git a/Tests/LibWeb/Layout/expected/table/bottom-caption.txt b/Tests/LibWeb/Layout/expected/table/bottom-caption.txt new file mode 100644 index 0000000000..0d08931822 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/table/bottom-caption.txt @@ -0,0 +1,69 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x91.875 [BFC] children: not-inline + BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline + TextNode <#text> + BlockContainer at (8,8) content-size 784x75.875 children: not-inline + TableWrapper <(anonymous)> at (8,8) content-size 95.171875x75.875 [BFC] children: not-inline + Box at (8,8) content-size 95.171875x58.40625 table-box [TFC] children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (8,66.40625) content-size 82.734375x17.46875 [BFC] children: inline + line 0 width: 82.734375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 1, length: 9, rect: [14,66.40625 82.734375x17.46875] + "A Caption" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (8,8) content-size 95.171875x19.46875 table-header-group children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (8,8) content-size 95.171875x19.46875 table-row children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (9,9) content-size 93.171875x17.46875 table-cell [BFC] children: inline + line 0 width: 73.65625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 9, rect: [9,9 73.65625x17.46875] + "Head Cell" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (8,27.46875) content-size 95.171875x19.46875 table-row-group children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (8,27.46875) content-size 95.171875x19.46875 table-row children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (9,28.46875) content-size 93.171875x17.46875 table-cell [BFC] children: inline + line 0 width: 70.234375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 9, rect: [9,28.46875 70.234375x17.46875] + "Body Cell" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (8,46.9375) content-size 95.171875x19.46875 table-footer-group children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (8,46.9375) content-size 95.171875x19.46875 table-row children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (9,47.9375) content-size 93.171875x17.46875 table-cell [BFC] children: inline + line 0 width: 93.171875, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 11, rect: [9,47.9375 93.171875x17.46875] + "Footer Cell" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,83.875) content-size 784x0 children: inline + TextNode <#text> diff --git a/Tests/LibWeb/Layout/expected/table/long-caption-increases-width.txt b/Tests/LibWeb/Layout/expected/table/long-caption-increases-width.txt new file mode 100644 index 0000000000..b16d3040cb --- /dev/null +++ b/Tests/LibWeb/Layout/expected/table/long-caption-increases-width.txt @@ -0,0 +1,96 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x138.21875 [BFC] children: not-inline + BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline + TextNode <#text> + BlockContainer at (8,8) content-size 784x122.21875 children: not-inline + TableWrapper <(anonymous)> at (8,8) content-size 55.046875x122.21875 [BFC] children: not-inline + Box at (10,61.8125) content-size 55.046875x64.40625 table-box [TFC] children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (8,8) content-size 59.046875x53.8125 [BFC] children: inline + line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 1, length: 1, rect: [22,8 14.265625x17.46875] + "A" + line 1 width: 31.765625, height: 17.9375, bottom: 35.40625, baseline: 13.53125 + frag 0 from TextNode start: 3, length: 4, rect: [14,25 31.765625x17.46875] + "long" + line 2 width: 59.046875, height: 18.40625, bottom: 53.34375, baseline: 13.53125 + frag 0 from TextNode start: 8, length: 7, rect: [8,42 59.046875x17.46875] + "caption" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (10,10) content-size 55.046875x21.46875 table-header-group children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (10,61.8125) content-size 55.046875x21.46875 table-row children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (12,63.8125) content-size 22.208835x17.46875 table-cell [BFC] children: inline + line 0 width: 20.609375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 2, rect: [12,63.8125 20.609375x17.46875] + "A1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (38.208835,63.8125) content-size 24.838039x17.46875 table-cell [BFC] children: inline + line 0 width: 23.078125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 2, rect: [38.208835,63.8125 23.078125x17.46875] + "A2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (10,31.46875) content-size 55.046875x21.46875 table-row-group children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (10,83.28125) content-size 55.046875x21.46875 table-row children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (12,85.28125) content-size 22.208835x17.46875 table-cell [BFC] children: inline + line 0 width: 15.6875, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 2, rect: [12,85.28125 15.6875x17.46875] + "B1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (38.208835,85.28125) content-size 24.838039x17.46875 table-cell [BFC] children: inline + line 0 width: 18.15625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 2, rect: [38.208835,85.28125 18.15625x17.46875] + "B2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (10,52.9375) content-size 55.046875x21.46875 table-footer-group children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + Box at (10,104.75) content-size 55.046875x21.46875 table-row children: not-inline + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (12,106.75) content-size 22.208835x17.46875 table-cell [BFC] children: inline + line 0 width: 18.890625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 2, rect: [12,106.75 18.890625x17.46875] + "F1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer at (38.208835,106.75) content-size 24.838039x17.46875 table-cell [BFC] children: inline + line 0 width: 21.359375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 2, rect: [38.208835,106.75 21.359375x17.46875] + "F2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> (not painted) children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,130.21875) content-size 784x0 children: inline + TextNode <#text> diff --git a/Tests/LibWeb/Layout/input/table/bottom-caption.html b/Tests/LibWeb/Layout/input/table/bottom-caption.html new file mode 100644 index 0000000000..9eeffd7fa2 --- /dev/null +++ b/Tests/LibWeb/Layout/input/table/bottom-caption.html @@ -0,0 +1,40 @@ + + + + + + Example of bottom caption + + + + + + + + + + + + + + + + + + + + + +
+ A Caption +
Head Cell
Body Cell
Footer Cell
+ + \ No newline at end of file diff --git a/Tests/LibWeb/Layout/input/table/long-caption-increases-width.html b/Tests/LibWeb/Layout/input/table/long-caption-increases-width.html new file mode 100644 index 0000000000..3ca7886d43 --- /dev/null +++ b/Tests/LibWeb/Layout/input/table/long-caption-increases-width.html @@ -0,0 +1,47 @@ + + + + + + Long caption increases table width + + + + + + + + + + + + + + + + + + + + + + + +
+ A long caption +
A1A2
B1B2
F1F2
+ + \ No newline at end of file diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 6aca2839cd..8c80073e28 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -35,6 +35,7 @@ public: static int font_weight() { return 400; } static CSS::FontVariant font_variant() { return CSS::FontVariant::Normal; } static CSS::Float float_() { return CSS::Float::None; } + static CSS::CaptionSide caption_side() { return CSS::CaptionSide::Top; } static CSS::Clear clear() { return CSS::Clear::None; } static CSS::Clip clip() { return CSS::Clip::make_auto(); } static CSS::Cursor cursor() { return CSS::Cursor::Auto; } @@ -220,6 +221,7 @@ class ComputedValues { public: AspectRatio aspect_ratio() const { return m_noninherited.aspect_ratio; } CSS::Float float_() const { return m_noninherited.float_; } + CSS::CaptionSide caption_side() const { return m_inherited.caption_side; } CSS::Clear clear() const { return m_noninherited.clear; } CSS::Clip clip() const { return m_noninherited.clip; } CSS::Cursor cursor() const { return m_inherited.cursor; } @@ -328,6 +330,7 @@ protected: float font_size { InitialValues::font_size() }; int font_weight { InitialValues::font_weight() }; CSS::FontVariant font_variant { InitialValues::font_variant() }; + CSS::CaptionSide caption_side { InitialValues::caption_side() }; Color color { InitialValues::color() }; Optional accent_color {}; CSS::Cursor cursor { InitialValues::cursor() }; @@ -431,6 +434,7 @@ public: void set_font_size(float font_size) { m_inherited.font_size = font_size; } void set_font_weight(int font_weight) { m_inherited.font_weight = font_weight; } void set_font_variant(CSS::FontVariant font_variant) { m_inherited.font_variant = font_variant; } + void set_caption_side(CSS::CaptionSide caption_side) { m_inherited.caption_side = caption_side; } void set_color(Color color) { m_inherited.color = color; } void set_clip(CSS::Clip const& clip) { m_noninherited.clip = clip; } void set_content(ContentData const& content) { m_noninherited.content = content; } diff --git a/Userland/Libraries/LibWeb/CSS/Enums.json b/Userland/Libraries/LibWeb/CSS/Enums.json index e8e31557f8..f47fb00bae 100644 --- a/Userland/Libraries/LibWeb/CSS/Enums.json +++ b/Userland/Libraries/LibWeb/CSS/Enums.json @@ -84,6 +84,10 @@ "border-box", "content-box" ], + "caption-side": [ + "top", + "bottom" + ], "clear": [ "none", "left", diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 1326993dc3..655fbb1dfa 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -628,9 +628,8 @@ "caption-side": { "inherited": true, "initial": "top", - "valid-identifiers": [ - "bottom", - "top" + "valid-types": [ + "caption-side" ] }, "clear": { diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp index 12ad2f26bb..dea11bded7 100644 --- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp +++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp @@ -523,6 +523,9 @@ ErrorOr> ResolvedCSSStyleDeclaration::style_value_for_p } case PropertyID::BoxSizing: return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().box_sizing())); + case PropertyID::CaptionSide: { + return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().caption_side())); + } case PropertyID::Clear: return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().clear())); case PropertyID::Clip: diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index dcdbfba6af..baba7375e7 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -373,6 +373,12 @@ Optional StyleProperties::image_rendering() const return value_id_to_image_rendering(value->to_identifier()); } +Optional StyleProperties::caption_side() const +{ + auto value = property(CSS::PropertyID::CaptionSide); + return value_id_to_caption_side(value->to_identifier()); +} + CSS::Clip StyleProperties::clip() const { auto value = property(CSS::PropertyID::Clip); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 4181c8e0fd..f1d6925c90 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -50,6 +50,7 @@ public: Color color_or_fallback(CSS::PropertyID, Layout::NodeWithStyle const&, Color fallback) const; Optional text_align() const; Optional text_justify() const; + Optional caption_side() const; CSS::Clip clip() const; CSS::Display display() const; Optional float_() const; diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index f74f6cb1b1..88dd19d2c2 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -52,6 +52,8 @@ public: virtual void determine_width_of_child(Box const&, AvailableSpace const&) override; virtual void determine_height_of_child(Box const&, AvailableSpace const&) override; + void resolve_vertical_box_model_metrics(Box const&); + private: CSSPixels compute_auto_height_for_block_level_element(Box const&, AvailableSpace const&); @@ -66,7 +68,6 @@ private: void layout_block_level_children(BlockContainer const&, LayoutMode, AvailableSpace const&); void layout_inline_children(BlockContainer const&, LayoutMode, AvailableSpace const&); - void resolve_vertical_box_model_metrics(Box const&); void place_block_level_element_in_normal_flow_horizontally(Box const& child_box, AvailableSpace const&); void place_block_level_element_in_normal_flow_vertically(Box const&, CSSPixels y); diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 20d1955cbd..4f70f82ee0 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -533,6 +533,10 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) if (float_.has_value()) computed_values.set_float(float_.value()); + auto caption_side = computed_style.caption_side(); + if (caption_side.has_value()) + computed_values.set_caption_side(caption_side.value()); + auto clear = computed_style.clear(); if (clear.has_value()) computed_values.set_clear(clear.value()); diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp index eeb007a0da..c9c1301c6d 100644 --- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,34 @@ static void for_each_child_box_matching(Box const& parent, Matcher matcher, Call }); } +CSSPixels TableFormattingContext::run_caption_layout(LayoutMode layout_mode, CSS::CaptionSide phase) +{ + CSSPixels caption_height = 0; + for (auto* child = table_box().first_child(); child; child = child->next_sibling()) { + if (!child->display().is_table_caption() || child->computed_values().caption_side() != phase) { + continue; + } + // The caption boxes are principal block-level boxes that retain their own content, padding, margin, and border areas, + // and are rendered as normal block boxes inside the table wrapper box, as described in https://www.w3.org/TR/CSS22/tables.html#model + auto caption_context = make(m_state, *verify_cast(child), this); + caption_context->run(table_box(), layout_mode, *m_available_space); + VERIFY(child->is_box()); + auto const& child_box = static_cast(*child); + // FIXME: Since caption only has inline children, BlockFormattingContext doesn't resolve the vertical metrics. + // We need to do it manually here. + caption_context->resolve_vertical_box_model_metrics(child_box); + auto const& caption_state = m_state.get(child_box); + if (phase == CSS::CaptionSide::Top) { + m_state.get_mutable(table_box()).set_content_y(caption_state.margin_box_height()); + } else { + m_state.get_mutable(child_box).set_content_y( + m_state.get(table_box()).margin_box_height() + caption_state.margin_box_top()); + } + caption_height += caption_state.margin_box_height(); + } + return caption_height; +} + void TableFormattingContext::calculate_row_column_grid(Box const& box) { // Implements https://html.spec.whatwg.org/multipage/tables.html#forming-a-table @@ -224,6 +253,21 @@ void TableFormattingContext::compute_table_measures() } } +CSSPixels TableFormattingContext::compute_capmin() +{ + // The caption width minimum (CAPMIN) is the largest of the table captions min-content contribution: + // https://drafts.csswg.org/css-tables-3/#computing-the-table-width + CSSPixels capmin = 0; + for (auto* child = table_box().first_child(); child; child = child->next_sibling()) { + if (!child->display().is_table_caption()) { + continue; + } + VERIFY(child->is_box()); + capmin = max(calculate_min_content_width(static_cast(*child)), capmin); + } + return capmin; +} + void TableFormattingContext::compute_table_width() { // https://drafts.csswg.org/css-tables-3/#computing-the-table-width @@ -253,7 +297,7 @@ void TableFormattingContext::compute_table_width() } // The used min-width of a table is the greater of the resolved min-width, CAPMIN, and GRIDMIN. - auto used_min_width = grid_min; + auto used_min_width = max(grid_min, compute_capmin()); if (!computed_values.min_width().is_auto()) { used_min_width = max(used_min_width, computed_values.min_width().to_px(table_box(), width_of_table_wrapper_containing_block)); } @@ -616,7 +660,7 @@ void TableFormattingContext::position_row_boxes(CSSPixels& total_content_height) { auto const& table_state = m_state.get(table_box()); - CSSPixels row_top_offset = table_state.border_top + table_state.padding_top; + CSSPixels row_top_offset = table_state.offset.y() + table_state.padding_top; CSSPixels row_left_offset = table_state.border_left + table_state.padding_left; for (size_t y = 0; y < m_rows.size(); y++) { auto& row = m_rows[y]; @@ -655,7 +699,7 @@ void TableFormattingContext::position_row_boxes(CSSPixels& total_content_height) row_group_top_offset += row_group_height; }); - total_content_height = max(row_top_offset, row_group_top_offset) - table_state.border_top - table_state.padding_top; + total_content_height = max(row_top_offset, row_group_top_offset) - table_state.offset.y() - table_state.padding_top; } void TableFormattingContext::position_cell_boxes() @@ -727,6 +771,8 @@ void TableFormattingContext::run(Box const& box, LayoutMode layout_mode, Availab { m_available_space = available_space; + auto total_captions_height = run_caption_layout(layout_mode, CSS::CaptionSide::Top); + CSSPixels total_content_height = 0; // Determine the number of rows/columns the table requires. @@ -755,6 +801,13 @@ void TableFormattingContext::run(Box const& box, LayoutMode layout_mode, Availab m_state.get_mutable(table_box()).set_content_height(total_content_height); + total_captions_height += run_caption_layout(layout_mode, CSS::CaptionSide::Bottom); + + // Table captions are positioned between the table margins and its borders (outside the grid box borders) as described in + // https://www.w3.org/TR/css-tables-3/#bounding-box-assignment + // A visual representation of this model can be found at https://www.w3.org/TR/css-tables-3/images/table_container.png + m_state.get_mutable(table_box()).margin_bottom += total_captions_height; + // FIXME: This is a total hack, we should respect the 'height' property. m_automatic_content_height = total_content_height; } diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h index c19872a73c..c58f22d36c 100644 --- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h @@ -28,6 +28,8 @@ public: } private: + CSSPixels run_caption_layout(LayoutMode, CSS::CaptionSide); + CSSPixels compute_capmin(); void calculate_row_column_grid(Box const&); void compute_table_measures(); void compute_table_width();