1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 21:47:46 +00:00

LibWeb: Add support for table caption

Adds layout support and the CSS caption-side property.
This commit is contained in:
Andi Gallo 2023-06-07 02:10:55 +00:00 committed by Andreas Kling
parent 656f72adc0
commit 940d9b98ae
15 changed files with 353 additions and 21 deletions

View file

@ -1,28 +1,31 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x58.40625 children: not-inline BlockContainer <body> at (8,8) content-size 784x75.875 children: not-inline
TableWrapper <(anonymous)> at (8,8) content-size 0x0 [BFC] children: not-inline TableWrapper <(anonymous)> at (8,8) content-size 0x0 [BFC] children: not-inline
Box <table#empty-table> at (8,8) content-size 0x0 table-box [TFC] children: not-inline Box <table#empty-table> at (8,8) content-size 0x0 table-box [TFC] children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text> TextNode <#text>
TextNode <#text> TextNode <#text>
TableWrapper <(anonymous)> at (8,8) content-size 95.171875x58.40625 [BFC] children: not-inline TableWrapper <(anonymous)> at (8,8) content-size 95.171875x75.875 [BFC] children: not-inline
Box <table#full-table> at (8,8) content-size 95.171875x58.40625 table-box [TFC] children: not-inline Box <table#full-table> at (8,25.46875) content-size 95.171875x58.40625 table-box [TFC] children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
BlockContainer <caption> (not painted) [BFC] children: inline BlockContainer <caption> 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> TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
Box <thead> at (8,8) content-size 95.171875x19.46875 table-header-group children: not-inline Box <thead> at (8,8) content-size 95.171875x19.46875 table-header-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
Box <tr> at (8,8) content-size 95.171875x19.46875 table-row children: not-inline Box <tr> at (8,25.46875) content-size 95.171875x19.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
BlockContainer <td> at (9,9) content-size 93.171875x17.46875 table-cell [BFC] children: inline BlockContainer <td> 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 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" "Head Cell"
TextNode <#text> TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
@ -34,12 +37,12 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
Box <tbody> at (8,27.46875) content-size 95.171875x19.46875 table-row-group children: not-inline Box <tbody> at (8,27.46875) content-size 95.171875x19.46875 table-row-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
Box <tr> at (8,27.46875) content-size 95.171875x19.46875 table-row children: not-inline Box <tr> at (8,44.9375) content-size 95.171875x19.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
BlockContainer <td> at (9,28.46875) content-size 93.171875x17.46875 table-cell [BFC] children: inline BlockContainer <td> 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 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" "Body Cell"
TextNode <#text> TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
@ -51,12 +54,12 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
Box <tfoot> at (8,46.9375) content-size 95.171875x19.46875 table-footer-group children: not-inline Box <tfoot> at (8,46.9375) content-size 95.171875x19.46875 table-footer-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
Box <tr> at (8,46.9375) content-size 95.171875x19.46875 table-row children: not-inline Box <tr> at (8,64.40625) content-size 95.171875x19.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> TextNode <#text>
BlockContainer <td> at (9,47.9375) content-size 93.171875x17.46875 table-cell [BFC] children: inline BlockContainer <td> 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 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" "Footer Cell"
TextNode <#text> TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
@ -65,5 +68,5 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
TextNode <#text> TextNode <#text>
BlockContainer <(anonymous)> (not painted) children: inline BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text> 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> TextNode <#text>

View file

@ -0,0 +1,69 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x91.875 [BFC] children: not-inline
BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline
TextNode <#text>
BlockContainer <body> 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 <table#full-table> at (8,8) content-size 95.171875x58.40625 table-box [TFC] children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <caption> 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 <thead> at (8,8) content-size 95.171875x19.46875 table-header-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tr> at (8,8) content-size 95.171875x19.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> 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 <tbody> at (8,27.46875) content-size 95.171875x19.46875 table-row-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tr> at (8,27.46875) content-size 95.171875x19.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> 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 <tfoot> at (8,46.9375) content-size 95.171875x19.46875 table-footer-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tr> at (8,46.9375) content-size 95.171875x19.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> 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>

View file

@ -0,0 +1,96 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x138.21875 [BFC] children: not-inline
BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline
TextNode <#text>
BlockContainer <body> 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 <table#full-table> at (10,61.8125) content-size 55.046875x64.40625 table-box [TFC] children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <caption> 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 <thead> at (10,10) content-size 55.046875x21.46875 table-header-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tr> at (10,61.8125) content-size 55.046875x21.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> 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 <td> 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 <tbody> at (10,31.46875) content-size 55.046875x21.46875 table-row-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tr> at (10,83.28125) content-size 55.046875x21.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> 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 <td> 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 <tfoot> at (10,52.9375) content-size 55.046875x21.46875 table-footer-group children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
Box <tr> at (10,104.75) content-size 55.046875x21.46875 table-row children: not-inline
BlockContainer <(anonymous)> (not painted) children: inline
TextNode <#text>
BlockContainer <td> 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 <td> 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>

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example of bottom caption</title>
<style>
* {
font-family: 'SerenitySans';
}
caption {
caption-side: bottom;
}
</style>
</head>
<table id="full-table">
<caption>
A Caption
</caption>
<thead>
<tr>
<td>Head Cell</td>
</tr>
</thead>
<tbody>
<tr>
<td>Body Cell</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>Footer Cell</td>
</tr>
</tfoot>
</table>
</html>

View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Long caption increases table width</title>
<style>
* {
font-family: 'SerenitySans';
}
table {
border: 2px solid black;
}
td,
th {
border: 1px solid black;
}
</style>
</head>
<table id="full-table">
<caption>
A long caption
</caption>
<thead>
<tr>
<td>A1</td>
<td>A2</td>
</tr>
</thead>
<tbody>
<tr>
<td>B1</td>
<td>B2</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>F1</td>
<td>F2</td>
</tr>
</tfoot>
</table>
</html>

View file

@ -35,6 +35,7 @@ public:
static int font_weight() { return 400; } static int font_weight() { return 400; }
static CSS::FontVariant font_variant() { return CSS::FontVariant::Normal; } static CSS::FontVariant font_variant() { return CSS::FontVariant::Normal; }
static CSS::Float float_() { return CSS::Float::None; } 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::Clear clear() { return CSS::Clear::None; }
static CSS::Clip clip() { return CSS::Clip::make_auto(); } static CSS::Clip clip() { return CSS::Clip::make_auto(); }
static CSS::Cursor cursor() { return CSS::Cursor::Auto; } static CSS::Cursor cursor() { return CSS::Cursor::Auto; }
@ -220,6 +221,7 @@ class ComputedValues {
public: public:
AspectRatio aspect_ratio() const { return m_noninherited.aspect_ratio; } AspectRatio aspect_ratio() const { return m_noninherited.aspect_ratio; }
CSS::Float float_() const { return m_noninherited.float_; } 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::Clear clear() const { return m_noninherited.clear; }
CSS::Clip clip() const { return m_noninherited.clip; } CSS::Clip clip() const { return m_noninherited.clip; }
CSS::Cursor cursor() const { return m_inherited.cursor; } CSS::Cursor cursor() const { return m_inherited.cursor; }
@ -328,6 +330,7 @@ protected:
float font_size { InitialValues::font_size() }; float font_size { InitialValues::font_size() };
int font_weight { InitialValues::font_weight() }; int font_weight { InitialValues::font_weight() };
CSS::FontVariant font_variant { InitialValues::font_variant() }; CSS::FontVariant font_variant { InitialValues::font_variant() };
CSS::CaptionSide caption_side { InitialValues::caption_side() };
Color color { InitialValues::color() }; Color color { InitialValues::color() };
Optional<Color> accent_color {}; Optional<Color> accent_color {};
CSS::Cursor cursor { InitialValues::cursor() }; 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_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_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_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_color(Color color) { m_inherited.color = color; }
void set_clip(CSS::Clip const& clip) { m_noninherited.clip = clip; } void set_clip(CSS::Clip const& clip) { m_noninherited.clip = clip; }
void set_content(ContentData const& content) { m_noninherited.content = content; } void set_content(ContentData const& content) { m_noninherited.content = content; }

View file

@ -84,6 +84,10 @@
"border-box", "border-box",
"content-box" "content-box"
], ],
"caption-side": [
"top",
"bottom"
],
"clear": [ "clear": [
"none", "none",
"left", "left",

View file

@ -628,9 +628,8 @@
"caption-side": { "caption-side": {
"inherited": true, "inherited": true,
"initial": "top", "initial": "top",
"valid-identifiers": [ "valid-types": [
"bottom", "caption-side"
"top"
] ]
}, },
"clear": { "clear": {

View file

@ -523,6 +523,9 @@ ErrorOr<RefPtr<StyleValue const>> ResolvedCSSStyleDeclaration::style_value_for_p
} }
case PropertyID::BoxSizing: case PropertyID::BoxSizing:
return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().box_sizing())); 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: case PropertyID::Clear:
return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().clear())); return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().clear()));
case PropertyID::Clip: case PropertyID::Clip:

View file

@ -373,6 +373,12 @@ Optional<CSS::ImageRendering> StyleProperties::image_rendering() const
return value_id_to_image_rendering(value->to_identifier()); return value_id_to_image_rendering(value->to_identifier());
} }
Optional<CSS::CaptionSide> StyleProperties::caption_side() const
{
auto value = property(CSS::PropertyID::CaptionSide);
return value_id_to_caption_side(value->to_identifier());
}
CSS::Clip StyleProperties::clip() const CSS::Clip StyleProperties::clip() const
{ {
auto value = property(CSS::PropertyID::Clip); auto value = property(CSS::PropertyID::Clip);

View file

@ -50,6 +50,7 @@ public:
Color color_or_fallback(CSS::PropertyID, Layout::NodeWithStyle const&, Color fallback) const; Color color_or_fallback(CSS::PropertyID, Layout::NodeWithStyle const&, Color fallback) const;
Optional<CSS::TextAlign> text_align() const; Optional<CSS::TextAlign> text_align() const;
Optional<CSS::TextJustify> text_justify() const; Optional<CSS::TextJustify> text_justify() const;
Optional<CSS::CaptionSide> caption_side() const;
CSS::Clip clip() const; CSS::Clip clip() const;
CSS::Display display() const; CSS::Display display() const;
Optional<CSS::Float> float_() const; Optional<CSS::Float> float_() const;

View file

@ -52,6 +52,8 @@ public:
virtual void determine_width_of_child(Box const&, AvailableSpace const&) override; virtual void determine_width_of_child(Box const&, AvailableSpace const&) override;
virtual void determine_height_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: private:
CSSPixels compute_auto_height_for_block_level_element(Box const&, AvailableSpace const&); 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_block_level_children(BlockContainer const&, LayoutMode, AvailableSpace const&);
void layout_inline_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_horizontally(Box const& child_box, AvailableSpace const&);
void place_block_level_element_in_normal_flow_vertically(Box const&, CSSPixels y); void place_block_level_element_in_normal_flow_vertically(Box const&, CSSPixels y);

View file

@ -533,6 +533,10 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
if (float_.has_value()) if (float_.has_value())
computed_values.set_float(float_.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(); auto clear = computed_style.clear();
if (clear.has_value()) if (clear.has_value())
computed_values.set_clear(clear.value()); computed_values.set_clear(clear.value());

View file

@ -7,6 +7,7 @@
#include <LibWeb/DOM/Node.h> #include <LibWeb/DOM/Node.h>
#include <LibWeb/HTML/BrowsingContext.h> #include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/HTMLTableCellElement.h> #include <LibWeb/HTML/HTMLTableCellElement.h>
#include <LibWeb/Layout/BlockFormattingContext.h>
#include <LibWeb/Layout/Box.h> #include <LibWeb/Layout/Box.h>
#include <LibWeb/Layout/InlineFormattingContext.h> #include <LibWeb/Layout/InlineFormattingContext.h>
#include <LibWeb/Layout/TableFormattingContext.h> #include <LibWeb/Layout/TableFormattingContext.h>
@ -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<BlockFormattingContext>(m_state, *verify_cast<BlockContainer>(child), this);
caption_context->run(table_box(), layout_mode, *m_available_space);
VERIFY(child->is_box());
auto const& child_box = static_cast<Box const&>(*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) void TableFormattingContext::calculate_row_column_grid(Box const& box)
{ {
// Implements https://html.spec.whatwg.org/multipage/tables.html#forming-a-table // 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<Box const&>(*child)), capmin);
}
return capmin;
}
void TableFormattingContext::compute_table_width() void TableFormattingContext::compute_table_width()
{ {
// https://drafts.csswg.org/css-tables-3/#computing-the-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. // 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()) { 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)); 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()); 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; CSSPixels row_left_offset = table_state.border_left + table_state.padding_left;
for (size_t y = 0; y < m_rows.size(); y++) { for (size_t y = 0; y < m_rows.size(); y++) {
auto& row = m_rows[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; 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() void TableFormattingContext::position_cell_boxes()
@ -727,6 +771,8 @@ void TableFormattingContext::run(Box const& box, LayoutMode layout_mode, Availab
{ {
m_available_space = available_space; m_available_space = available_space;
auto total_captions_height = run_caption_layout(layout_mode, CSS::CaptionSide::Top);
CSSPixels total_content_height = 0; CSSPixels total_content_height = 0;
// Determine the number of rows/columns the table requires. // 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); 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. // FIXME: This is a total hack, we should respect the 'height' property.
m_automatic_content_height = total_content_height; m_automatic_content_height = total_content_height;
} }

View file

@ -28,6 +28,8 @@ public:
} }
private: private:
CSSPixels run_caption_layout(LayoutMode, CSS::CaptionSide);
CSSPixels compute_capmin();
void calculate_row_column_grid(Box const&); void calculate_row_column_grid(Box const&);
void compute_table_measures(); void compute_table_measures();
void compute_table_width(); void compute_table_width();