mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:48:10 +00:00
LibWeb: Start work towards modern CSS "display" values
Until now, we've internally thought of the CSS "display" property as a single-value property. In practice, "display" is a much more complex property that comes in a number of configurations. The most interesting one is the two-part format that describes the outside and inside behavior of a box. Switching our own internal representation towards this model will allow for much cleaner abstractions around layout and the various formatting contexts. Note that we don't *parse* two-part "display" yet, this is only about changing the internal representation of the property. Spec: https://drafts.csswg.org/css-display
This commit is contained in:
parent
1552873275
commit
85a0772147
22 changed files with 214 additions and 161 deletions
|
@ -22,7 +22,7 @@ public:
|
|||
static CSS::Position position() { return CSS::Position::Static; }
|
||||
static CSS::TextDecorationLine text_decoration_line() { return CSS::TextDecorationLine::None; }
|
||||
static CSS::TextTransform text_transform() { return CSS::TextTransform::None; }
|
||||
static CSS::Display display() { return CSS::Display::Inline; }
|
||||
static CSS::Display display() { return CSS::Display { CSS::Display::Outside::Inline, CSS::Display::Inside::Flow }; }
|
||||
static Color color() { return Color::Black; }
|
||||
static Color background_color() { return Color::Transparent; }
|
||||
static CSS::Repeat background_repeat() { return CSS::Repeat::Repeat; }
|
||||
|
|
|
@ -44,41 +44,78 @@ static CSS::ValueID to_css_value_id(CSS::BoxSizing value)
|
|||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
static CSS::ValueID to_css_value_id(CSS::Display value)
|
||||
static RefPtr<StyleValue> style_value_for_display(CSS::Display display)
|
||||
{
|
||||
switch (value) {
|
||||
case CSS::Display::None:
|
||||
return CSS::ValueID::None;
|
||||
case CSS::Display::Block:
|
||||
return CSS::ValueID::Block;
|
||||
case CSS::Display::Inline:
|
||||
return CSS::ValueID::Inline;
|
||||
case CSS::Display::InlineBlock:
|
||||
return CSS::ValueID::InlineBlock;
|
||||
case CSS::Display::ListItem:
|
||||
return CSS::ValueID::ListItem;
|
||||
case CSS::Display::Table:
|
||||
return CSS::ValueID::Table;
|
||||
case CSS::Display::TableRow:
|
||||
return CSS::ValueID::TableRow;
|
||||
case CSS::Display::TableCell:
|
||||
return CSS::ValueID::TableCell;
|
||||
case CSS::Display::TableHeaderGroup:
|
||||
return CSS::ValueID::TableHeaderGroup;
|
||||
case CSS::Display::TableRowGroup:
|
||||
return CSS::ValueID::TableRowGroup;
|
||||
case CSS::Display::TableFooterGroup:
|
||||
return CSS::ValueID::TableFooterGroup;
|
||||
case CSS::Display::TableColumn:
|
||||
return CSS::ValueID::TableColumn;
|
||||
case CSS::Display::TableColumnGroup:
|
||||
return CSS::ValueID::TableColumnGroup;
|
||||
case CSS::Display::TableCaption:
|
||||
return CSS::ValueID::TableCaption;
|
||||
case CSS::Display::Flex:
|
||||
return CSS::ValueID::Flex;
|
||||
if (display.is_none())
|
||||
return IdentifierStyleValue::create(CSS::ValueID::None);
|
||||
|
||||
if (display.it_outside_and_inside()) {
|
||||
NonnullRefPtrVector<StyleValue> values;
|
||||
switch (display.outside()) {
|
||||
case CSS::Display::Outside::Inline:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::Inline));
|
||||
break;
|
||||
case CSS::Display::Outside::Block:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::Block));
|
||||
break;
|
||||
case CSS::Display::Outside::RunIn:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::RunIn));
|
||||
break;
|
||||
}
|
||||
switch (display.inside()) {
|
||||
case CSS::Display::Inside::Flow:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::Flow));
|
||||
break;
|
||||
case CSS::Display::Inside::FlowRoot:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::FlowRoot));
|
||||
break;
|
||||
case CSS::Display::Inside::Table:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::Table));
|
||||
break;
|
||||
case CSS::Display::Inside::Flex:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::Flex));
|
||||
break;
|
||||
case CSS::Display::Inside::Grid:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::Grid));
|
||||
break;
|
||||
case CSS::Display::Inside::Ruby:
|
||||
values.append(IdentifierStyleValue::create(CSS::ValueID::Ruby));
|
||||
break;
|
||||
}
|
||||
|
||||
return StyleValueList::create(move(values));
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
|
||||
if (display.is_internal()) {
|
||||
switch (display.internal()) {
|
||||
case CSS::Display::Internal::TableRowGroup:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableRowGroup);
|
||||
case CSS::Display::Internal::TableHeaderGroup:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableHeaderGroup);
|
||||
case CSS::Display::Internal::TableFooterGroup:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableFooterGroup);
|
||||
case CSS::Display::Internal::TableRow:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableRow);
|
||||
case CSS::Display::Internal::TableCell:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableCell);
|
||||
case CSS::Display::Internal::TableColumnGroup:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableColumnGroup);
|
||||
case CSS::Display::Internal::TableColumn:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableColumn);
|
||||
case CSS::Display::Internal::TableCaption:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::TableCaption);
|
||||
case CSS::Display::Internal::RubyBase:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::RubyBase);
|
||||
case CSS::Display::Internal::RubyText:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::RubyText);
|
||||
case CSS::Display::Internal::RubyBaseContainer:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::RubyBaseContainer);
|
||||
case CSS::Display::Internal::RubyTextContainer:
|
||||
return IdentifierStyleValue::create(CSS::ValueID::RubyTextContainer);
|
||||
}
|
||||
}
|
||||
|
||||
TODO();
|
||||
}
|
||||
|
||||
static CSS::ValueID to_css_value_id(CSS::Float value)
|
||||
|
@ -427,7 +464,7 @@ RefPtr<StyleValue> ResolvedCSSStyleDeclaration::style_value_for_property(Layout:
|
|||
case CSS::PropertyID::Cursor:
|
||||
return IdentifierStyleValue::create(to_css_value_id(layout_node.computed_values().cursor()));
|
||||
case CSS::PropertyID::Display:
|
||||
return IdentifierStyleValue::create(to_css_value_id(layout_node.computed_values().display()));
|
||||
return style_value_for_display(layout_node.computed_values().display());
|
||||
case CSS::PropertyID::ZIndex: {
|
||||
auto maybe_z_index = layout_node.computed_values().z_index();
|
||||
if (!maybe_z_index.has_value())
|
||||
|
|
|
@ -530,40 +530,40 @@ CSS::Display StyleProperties::display() const
|
|||
{
|
||||
auto value = property(CSS::PropertyID::Display);
|
||||
if (!value.has_value() || !value.value()->is_identifier())
|
||||
return CSS::Display::Inline;
|
||||
return CSS::Display::from_short(CSS::Display::Short::Inline);
|
||||
switch (value.value()->to_identifier()) {
|
||||
case CSS::ValueID::None:
|
||||
return CSS::Display::None;
|
||||
return CSS::Display::from_short(CSS::Display::Short::None);
|
||||
case CSS::ValueID::Block:
|
||||
return CSS::Display::Block;
|
||||
return CSS::Display::from_short(CSS::Display::Short::Block);
|
||||
case CSS::ValueID::Inline:
|
||||
return CSS::Display::Inline;
|
||||
return CSS::Display::from_short(CSS::Display::Short::Inline);
|
||||
case CSS::ValueID::InlineBlock:
|
||||
return CSS::Display::InlineBlock;
|
||||
return CSS::Display::from_short(CSS::Display::Short::InlineBlock);
|
||||
case CSS::ValueID::ListItem:
|
||||
return CSS::Display::ListItem;
|
||||
return CSS::Display::from_short(CSS::Display::Short::ListItem);
|
||||
case CSS::ValueID::Table:
|
||||
return CSS::Display::Table;
|
||||
return CSS::Display::from_short(CSS::Display::Short::Table);
|
||||
case CSS::ValueID::TableRow:
|
||||
return CSS::Display::TableRow;
|
||||
return CSS::Display { CSS::Display::Internal::TableRow };
|
||||
case CSS::ValueID::TableCell:
|
||||
return CSS::Display::TableCell;
|
||||
return CSS::Display { CSS::Display::Internal::TableCell };
|
||||
case CSS::ValueID::TableColumn:
|
||||
return CSS::Display::TableColumn;
|
||||
return CSS::Display { CSS::Display::Internal::TableColumn };
|
||||
case CSS::ValueID::TableColumnGroup:
|
||||
return CSS::Display::TableColumnGroup;
|
||||
return CSS::Display { CSS::Display::Internal::TableColumnGroup };
|
||||
case CSS::ValueID::TableCaption:
|
||||
return CSS::Display::TableCaption;
|
||||
return CSS::Display { CSS::Display::Internal::TableCaption };
|
||||
case CSS::ValueID::TableRowGroup:
|
||||
return CSS::Display::TableRowGroup;
|
||||
return CSS::Display { CSS::Display::Internal::TableRowGroup };
|
||||
case CSS::ValueID::TableHeaderGroup:
|
||||
return CSS::Display::TableHeaderGroup;
|
||||
return CSS::Display { CSS::Display::Internal::TableHeaderGroup };
|
||||
case CSS::ValueID::TableFooterGroup:
|
||||
return CSS::Display::TableFooterGroup;
|
||||
return CSS::Display { CSS::Display::Internal::TableFooterGroup };
|
||||
case CSS::ValueID::Flex:
|
||||
return CSS::Display::Flex;
|
||||
return CSS::Display::from_short(CSS::Display::Short::Flex);
|
||||
default:
|
||||
return CSS::Display::Block;
|
||||
return CSS::Display::from_short(CSS::Display::Short::Block);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <AK/WeakPtr.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibWeb/CSS/Display.h>
|
||||
#include <LibWeb/CSS/Length.h>
|
||||
#include <LibWeb/CSS/Parser/StyleComponentValueRule.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
|
@ -90,24 +91,6 @@ enum class Cursor {
|
|||
ZoomOut,
|
||||
};
|
||||
|
||||
enum class Display {
|
||||
None,
|
||||
Block,
|
||||
Inline,
|
||||
InlineBlock,
|
||||
ListItem,
|
||||
Table,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableHeaderGroup,
|
||||
TableRowGroup,
|
||||
TableFooterGroup,
|
||||
TableColumn,
|
||||
TableColumnGroup,
|
||||
TableCaption,
|
||||
Flex,
|
||||
};
|
||||
|
||||
enum class FlexBasis {
|
||||
Content,
|
||||
Length,
|
||||
|
|
|
@ -110,48 +110,48 @@ RefPtr<Layout::Node> Element::create_layout_node()
|
|||
const_cast<Element&>(*this).m_specified_css_values = style;
|
||||
auto display = style->display();
|
||||
|
||||
if (display == CSS::Display::None)
|
||||
if (display.is_none())
|
||||
return nullptr;
|
||||
|
||||
if (local_name() == "noscript" && document().is_scripting_enabled())
|
||||
return nullptr;
|
||||
|
||||
switch (display) {
|
||||
case CSS::Display::None:
|
||||
VERIFY_NOT_REACHED();
|
||||
break;
|
||||
case CSS::Display::Block:
|
||||
return adopt_ref(*new Layout::BlockBox(document(), this, move(style)));
|
||||
case CSS::Display::Inline:
|
||||
if (style->float_().value_or(CSS::Float::None) != CSS::Float::None)
|
||||
return adopt_ref(*new Layout::BlockBox(document(), this, move(style)));
|
||||
return adopt_ref(*new Layout::InlineNode(document(), *this, move(style)));
|
||||
case CSS::Display::ListItem:
|
||||
return adopt_ref(*new Layout::ListItemBox(document(), *this, move(style)));
|
||||
case CSS::Display::Table:
|
||||
if (display.is_table_inside())
|
||||
return adopt_ref(*new Layout::TableBox(document(), this, move(style)));
|
||||
case CSS::Display::TableRow:
|
||||
|
||||
if (display.is_list_item())
|
||||
return adopt_ref(*new Layout::ListItemBox(document(), *this, move(style)));
|
||||
|
||||
if (display.is_table_row())
|
||||
return adopt_ref(*new Layout::TableRowBox(document(), this, move(style)));
|
||||
case CSS::Display::TableCell:
|
||||
|
||||
if (display.is_table_cell())
|
||||
return adopt_ref(*new Layout::TableCellBox(document(), this, move(style)));
|
||||
case CSS::Display::TableRowGroup:
|
||||
case CSS::Display::TableHeaderGroup:
|
||||
case CSS::Display::TableFooterGroup:
|
||||
|
||||
if (display.is_table_row_group() || display.is_table_header_group() || display.is_table_footer_group())
|
||||
return adopt_ref(*new Layout::TableRowGroupBox(document(), *this, move(style)));
|
||||
case CSS::Display::InlineBlock: {
|
||||
auto inline_block = adopt_ref(*new Layout::BlockBox(document(), this, move(style)));
|
||||
inline_block->set_inline(true);
|
||||
return inline_block;
|
||||
}
|
||||
case CSS::Display::Flex:
|
||||
return adopt_ref(*new Layout::BlockBox(document(), this, move(style)));
|
||||
case CSS::Display::TableColumn:
|
||||
case CSS::Display::TableColumnGroup:
|
||||
case CSS::Display::TableCaption:
|
||||
|
||||
if (display.is_table_column() || display.is_table_column_group() || display.is_table_caption()) {
|
||||
// FIXME: This is just an incorrect placeholder until we improve table layout support.
|
||||
return adopt_ref(*new Layout::BlockBox(document(), this, move(style)));
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
|
||||
if (display.is_inline_outside()) {
|
||||
if (display.is_flow_root_inside()) {
|
||||
auto block = adopt_ref(*new Layout::BlockBox(document(), this, move(style)));
|
||||
block->set_inline(true);
|
||||
return block;
|
||||
}
|
||||
if (display.is_flow_inside())
|
||||
return adopt_ref(*new Layout::InlineNode(document(), *this, move(style)));
|
||||
|
||||
TODO();
|
||||
}
|
||||
|
||||
if (display.is_flow_inside() || display.is_flow_root_inside() || display.is_flex_inside())
|
||||
return adopt_ref(*new Layout::BlockBox(document(), this, move(style)));
|
||||
|
||||
TODO();
|
||||
}
|
||||
|
||||
void Element::parse_attribute(const FlyString& name, const String& value)
|
||||
|
@ -209,7 +209,7 @@ void Element::recompute_style()
|
|||
auto new_specified_css_values = document().style_computer().compute_style(*this);
|
||||
m_specified_css_values = new_specified_css_values;
|
||||
if (!layout_node()) {
|
||||
if (new_specified_css_values->display() == CSS::Display::None)
|
||||
if (new_specified_css_values->display().is_none())
|
||||
return;
|
||||
// We need a new layout tree here!
|
||||
Layout::TreeBuilder tree_builder;
|
||||
|
|
|
@ -176,7 +176,7 @@ void dump_tree(StringBuilder& builder, Layout::Node const& layout_node, bool sho
|
|||
builder.appendff(" {}floating{}", floating_color_on, color_off);
|
||||
if (box.is_inline_block())
|
||||
builder.appendff(" {}inline-block{}", inline_block_color_on, color_off);
|
||||
if (box.computed_values().display() == CSS::Display::Flex)
|
||||
if (box.computed_values().display().is_flex_inside())
|
||||
builder.appendff(" {}flex-container{}", flex_color_on, color_off);
|
||||
if (box.is_flex_item())
|
||||
builder.appendff(" {}flex-item{}", flex_color_on, color_off);
|
||||
|
|
|
@ -26,6 +26,7 @@ class CSSRuleList;
|
|||
class CSSStyleDeclaration;
|
||||
class CSSStyleRule;
|
||||
class CSSStyleSheet;
|
||||
class Display;
|
||||
class ElementInlineCSSStyleDeclaration;
|
||||
class Length;
|
||||
class MediaList;
|
||||
|
@ -38,7 +39,6 @@ class Selector;
|
|||
class StyleProperties;
|
||||
class StyleComputer;
|
||||
class StyleSheet;
|
||||
enum class Display;
|
||||
|
||||
class StyleValue;
|
||||
class BackgroundRepeatStyleValue;
|
||||
|
|
|
@ -22,7 +22,7 @@ HTMLBRElement::~HTMLBRElement()
|
|||
RefPtr<Layout::Node> HTMLBRElement::create_layout_node()
|
||||
{
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
return adopt_ref(*new Layout::BreakNode(document(), *this, move(style)));
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ unsigned HTMLCanvasElement::height() const
|
|||
RefPtr<Layout::Node> HTMLCanvasElement::create_layout_node()
|
||||
{
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
return adopt_ref(*new Layout::CanvasBox(document(), *this, move(style)));
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ void HTMLImageElement::parse_attribute(const FlyString& name, const String& valu
|
|||
RefPtr<Layout::Node> HTMLImageElement::create_layout_node()
|
||||
{
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
return adopt_ref(*new Layout::ImageBox(document(), *this, move(style), m_image_loader));
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ RefPtr<Layout::Node> HTMLInputElement::create_layout_node()
|
|||
return nullptr;
|
||||
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
|
||||
if (type().equals_ignoring_case("submit") || type().equals_ignoring_case("button"))
|
||||
|
|
|
@ -22,7 +22,7 @@ HTMLLabelElement::~HTMLLabelElement()
|
|||
RefPtr<Layout::Node> HTMLLabelElement::create_layout_node()
|
||||
{
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
|
||||
auto layout_node = adopt_ref(*new Layout::Label(document(), this, move(style)));
|
||||
|
|
|
@ -47,7 +47,7 @@ RefPtr<Layout::Node> HTMLObjectElement::create_layout_node()
|
|||
return HTMLElement::create_layout_node();
|
||||
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
if (m_image_loader.has_image())
|
||||
return adopt_ref(*new Layout::ImageBox(document(), *this, move(style), m_image_loader));
|
||||
|
|
|
@ -50,16 +50,23 @@ bool FormattingContext::creates_block_formatting_context(const Box& box)
|
|||
if ((overflow_y != CSS::Overflow::Visible) && (overflow_y != CSS::Overflow::Clip))
|
||||
return true;
|
||||
|
||||
auto display = box.computed_values().display();
|
||||
|
||||
if (display.is_flow_root_inside())
|
||||
return true;
|
||||
|
||||
// FIXME: inline-flex as well
|
||||
if (box.parent() && box.parent()->computed_values().display() == CSS::Display::Flex) {
|
||||
// FIXME: Flex items (direct children of the element with display: flex or inline-flex) if they are neither flex nor grid nor table containers themselves.
|
||||
if (box.computed_values().display() != CSS::Display::Flex)
|
||||
return true;
|
||||
if (box.parent()) {
|
||||
auto parent_display = box.parent()->computed_values().display();
|
||||
if (parent_display.is_flex_inside()) {
|
||||
// FIXME: Flex items (direct children of the element with display: flex or inline-flex) if they are neither flex nor grid nor table containers themselves.
|
||||
if (!display.is_flex_inside())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: table-caption
|
||||
// FIXME: anonymous table cells
|
||||
// FIXME: display: flow-root
|
||||
// FIXME: Elements with contain: layout, content, or paint.
|
||||
// FIXME: grid
|
||||
// FIXME: multicol
|
||||
|
@ -67,37 +74,46 @@ bool FormattingContext::creates_block_formatting_context(const Box& box)
|
|||
return false;
|
||||
}
|
||||
|
||||
void FormattingContext::layout_inside(Box& box, LayoutMode layout_mode)
|
||||
void FormattingContext::layout_inside(Box& child_box, LayoutMode layout_mode)
|
||||
{
|
||||
if (is<SVGSVGBox>(box)) {
|
||||
SVGFormattingContext context(box, this);
|
||||
context.run(box, layout_mode);
|
||||
auto context_display = context_box().computed_values().display();
|
||||
|
||||
if (is<SVGSVGBox>(child_box)) {
|
||||
SVGFormattingContext context(child_box, this);
|
||||
context.run(child_box, layout_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (box.computed_values().display() == CSS::Display::Flex) {
|
||||
FlexFormattingContext context(box, this);
|
||||
context.run(box, layout_mode);
|
||||
auto child_display = child_box.computed_values().display();
|
||||
|
||||
if (child_display.is_flex_inside()) {
|
||||
FlexFormattingContext context(child_box, this);
|
||||
context.run(child_box, layout_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (creates_block_formatting_context(box)) {
|
||||
BlockFormattingContext context(box, this);
|
||||
context.run(box, layout_mode);
|
||||
if (creates_block_formatting_context(child_box)) {
|
||||
BlockFormattingContext context(child_box, this);
|
||||
context.run(child_box, layout_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is<TableBox>(box)) {
|
||||
TableFormattingContext context(box, this);
|
||||
context.run(box, layout_mode);
|
||||
} else if (box.children_are_inline()) {
|
||||
InlineFormattingContext context(box, this);
|
||||
context.run(box, layout_mode);
|
||||
} else {
|
||||
// FIXME: This needs refactoring!
|
||||
VERIFY(is_block_formatting_context());
|
||||
run(box, layout_mode);
|
||||
if (child_display.is_table_inside()) {
|
||||
TableFormattingContext context(child_box, this);
|
||||
context.run(child_box, layout_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
VERIFY(is_block_formatting_context());
|
||||
|
||||
if (child_box.children_are_inline()) {
|
||||
InlineFormattingContext context(child_box, this);
|
||||
context.run(child_box, layout_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
VERIFY(child_display.is_flow_inside());
|
||||
run(child_box, layout_mode);
|
||||
}
|
||||
|
||||
static float greatest_child_width(const Box& box)
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
TableBox(DOM::Document&, DOM::Element*, CSS::ComputedValues);
|
||||
virtual ~TableBox() override;
|
||||
|
||||
static CSS::Display static_display() { return CSS::Display::Table; }
|
||||
static CSS::Display static_display() { return CSS::Display::from_short(CSS::Display::Short::Table); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
|
||||
size_t colspan() const;
|
||||
|
||||
static CSS::Display static_display() { return CSS::Display::TableCell; }
|
||||
static CSS::Display static_display() { return CSS::Display { CSS::Display::Internal::TableCell }; }
|
||||
|
||||
private:
|
||||
virtual float width_of_logical_containing_block() const override;
|
||||
|
|
|
@ -16,7 +16,7 @@ public:
|
|||
TableRowBox(DOM::Document&, DOM::Element*, CSS::ComputedValues);
|
||||
virtual ~TableRowBox() override;
|
||||
|
||||
static CSS::Display static_display() { return CSS::Display::TableRow; }
|
||||
static CSS::Display static_display() { return CSS::Display { CSS::Display::Internal::TableRow }; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ static Layout::Node& insertion_parent_for_inline_node(Layout::NodeWithStyle& lay
|
|||
if (layout_parent.is_inline() && !layout_parent.is_inline_block())
|
||||
return layout_parent;
|
||||
|
||||
if (layout_parent.computed_values().display() == CSS::Display::Flex) {
|
||||
if (layout_parent.computed_values().display().is_flex_inside()) {
|
||||
layout_parent.append_child(layout_parent.create_anonymous_wrapper());
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
if (!dom_node.parent_or_shadow_host()) {
|
||||
m_layout_root = layout_node;
|
||||
} else {
|
||||
if (layout_node->is_inline() && !(layout_node->is_inline_block() && m_parent_stack.last()->computed_values().display() == CSS::Display::Flex)) {
|
||||
if (layout_node->is_inline() && !(layout_node->is_inline_block() && m_parent_stack.last()->computed_values().display().is_flex_inside())) {
|
||||
// Inlines can be inserted into the nearest ancestor.
|
||||
auto& insertion_point = insertion_parent_for_inline_node(*m_parent_stack.last());
|
||||
insertion_point.append_child(*layout_node);
|
||||
|
@ -147,11 +147,23 @@ RefPtr<Node> TreeBuilder::build(DOM::Node& dom_node)
|
|||
return move(m_layout_root);
|
||||
}
|
||||
|
||||
template<CSS::Display display, typename Callback>
|
||||
void TreeBuilder::for_each_in_tree_with_display(NodeWithStyle& root, Callback callback)
|
||||
template<CSS::Display::Internal internal, typename Callback>
|
||||
void TreeBuilder::for_each_in_tree_with_internal_display(NodeWithStyle& root, Callback callback)
|
||||
{
|
||||
root.for_each_in_inclusive_subtree_of_type<Box>([&](auto& box) {
|
||||
if (box.computed_values().display() == display)
|
||||
auto const& display = box.computed_values().display();
|
||||
if (display.is_internal() && display.internal() == internal)
|
||||
callback(box);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
template<CSS::Display::Inside inside, typename Callback>
|
||||
void TreeBuilder::for_each_in_tree_with_inside_display(NodeWithStyle& root, Callback callback)
|
||||
{
|
||||
root.for_each_in_inclusive_subtree_of_type<Box>([&](auto& box) {
|
||||
auto const& display = box.computed_values().display();
|
||||
if (display.it_outside_and_inside() && display.inside() == inside)
|
||||
callback(box);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
@ -173,16 +185,16 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root)
|
|||
NonnullRefPtrVector<Node> to_remove;
|
||||
|
||||
// Children of a table-column.
|
||||
for_each_in_tree_with_display<CSS::Display::TableColumn>(root, [&](Box& table_column) {
|
||||
for_each_in_tree_with_internal_display<CSS::Display::Internal::TableColumn>(root, [&](Box& table_column) {
|
||||
table_column.for_each_child([&](auto& child) {
|
||||
to_remove.append(child);
|
||||
});
|
||||
});
|
||||
|
||||
// Children of a table-column-group which are not a table-column.
|
||||
for_each_in_tree_with_display<CSS::Display::TableColumnGroup>(root, [&](Box& table_column_group) {
|
||||
for_each_in_tree_with_internal_display<CSS::Display::Internal::TableColumnGroup>(root, [&](Box& table_column_group) {
|
||||
table_column_group.for_each_child([&](auto& child) {
|
||||
if (child.computed_values().display() != CSS::Display::TableColumn)
|
||||
if (child.computed_values().display().is_table_column())
|
||||
to_remove.append(child);
|
||||
});
|
||||
});
|
||||
|
@ -200,15 +212,17 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root)
|
|||
|
||||
static bool is_table_track(CSS::Display display)
|
||||
{
|
||||
return display == CSS::Display::TableRow || display == CSS::Display::TableColumn;
|
||||
return display.is_table_row() || display.is_table_column();
|
||||
}
|
||||
|
||||
static bool is_table_track_group(CSS::Display display)
|
||||
{
|
||||
// Unless explicitly mentioned otherwise, mentions of table-row-groups in this spec also encompass the specialized
|
||||
// table-header-groups and table-footer-groups.
|
||||
return display == CSS::Display::TableRowGroup || display == CSS::Display::TableHeaderGroup || display == CSS::Display::TableFooterGroup
|
||||
|| display == CSS::Display::TableColumnGroup;
|
||||
return display.is_table_row_group()
|
||||
|| display.is_table_header_group()
|
||||
|| display.is_table_footer_group()
|
||||
|| display.is_table_column_group();
|
||||
}
|
||||
|
||||
static bool is_not_proper_table_child(const Node& node)
|
||||
|
@ -216,7 +230,7 @@ static bool is_not_proper_table_child(const Node& node)
|
|||
if (!node.has_style())
|
||||
return true;
|
||||
auto display = node.computed_values().display();
|
||||
return !is_table_track_group(display) && !is_table_track(display) && display != CSS::Display::TableCaption;
|
||||
return !is_table_track_group(display) && !is_table_track(display) && !display.is_table_caption();
|
||||
}
|
||||
|
||||
static bool is_not_table_row(const Node& node)
|
||||
|
@ -224,7 +238,7 @@ static bool is_not_table_row(const Node& node)
|
|||
if (!node.has_style())
|
||||
return true;
|
||||
auto display = node.computed_values().display();
|
||||
return display != CSS::Display::TableRow;
|
||||
return !display.is_table_row();
|
||||
}
|
||||
|
||||
static bool is_not_table_cell(const Node& node)
|
||||
|
@ -232,7 +246,7 @@ static bool is_not_table_cell(const Node& node)
|
|||
if (!node.has_style())
|
||||
return true;
|
||||
auto display = node.computed_values().display();
|
||||
return display != CSS::Display::TableCell;
|
||||
return !display.is_table_cell();
|
||||
}
|
||||
|
||||
template<typename Matcher, typename Callback>
|
||||
|
@ -276,33 +290,33 @@ static void wrap_in_anonymous(NonnullRefPtrVector<Node>& sequence, Node* nearest
|
|||
void TreeBuilder::generate_missing_child_wrappers(NodeWithStyle& root)
|
||||
{
|
||||
// An anonymous table-row box must be generated around each sequence of consecutive children of a table-root box which are not proper table child boxes.
|
||||
for_each_in_tree_with_display<CSS::Display::Table>(root, [&](auto& parent) {
|
||||
for_each_in_tree_with_inside_display<CSS::Display::Inside::Table>(root, [&](auto& parent) {
|
||||
for_each_sequence_of_consecutive_children_matching(parent, is_not_proper_table_child, [&](auto sequence, auto nearest_sibling) {
|
||||
wrap_in_anonymous<TableRowBox>(sequence, nearest_sibling);
|
||||
});
|
||||
});
|
||||
|
||||
// An anonymous table-row box must be generated around each sequence of consecutive children of a table-row-group box which are not table-row boxes.
|
||||
for_each_in_tree_with_display<CSS::Display::TableRowGroup>(root, [&](auto& parent) {
|
||||
for_each_in_tree_with_internal_display<CSS::Display::Internal::TableRowGroup>(root, [&](auto& parent) {
|
||||
for_each_sequence_of_consecutive_children_matching(parent, is_not_table_row, [&](auto& sequence, auto nearest_sibling) {
|
||||
wrap_in_anonymous<TableRowBox>(sequence, nearest_sibling);
|
||||
});
|
||||
});
|
||||
// Unless explicitly mentioned otherwise, mentions of table-row-groups in this spec also encompass the specialized
|
||||
// table-header-groups and table-footer-groups.
|
||||
for_each_in_tree_with_display<CSS::Display::TableHeaderGroup>(root, [&](auto& parent) {
|
||||
for_each_in_tree_with_internal_display<CSS::Display::Internal::TableHeaderGroup>(root, [&](auto& parent) {
|
||||
for_each_sequence_of_consecutive_children_matching(parent, is_not_table_row, [&](auto& sequence, auto nearest_sibling) {
|
||||
wrap_in_anonymous<TableRowBox>(sequence, nearest_sibling);
|
||||
});
|
||||
});
|
||||
for_each_in_tree_with_display<CSS::Display::TableFooterGroup>(root, [&](auto& parent) {
|
||||
for_each_in_tree_with_internal_display<CSS::Display::Internal::TableFooterGroup>(root, [&](auto& parent) {
|
||||
for_each_sequence_of_consecutive_children_matching(parent, is_not_table_row, [&](auto& sequence, auto nearest_sibling) {
|
||||
wrap_in_anonymous<TableRowBox>(sequence, nearest_sibling);
|
||||
});
|
||||
});
|
||||
|
||||
// An anonymous table-cell box must be generated around each sequence of consecutive children of a table-row box which are not table-cell boxes. !Testcase
|
||||
for_each_in_tree_with_display<CSS::Display::TableRow>(root, [&](auto& parent) {
|
||||
for_each_in_tree_with_internal_display<CSS::Display::Internal::TableRow>(root, [&](auto& parent) {
|
||||
for_each_sequence_of_consecutive_children_matching(parent, is_not_table_cell, [&](auto& sequence, auto nearest_sibling) {
|
||||
wrap_in_anonymous<TableCellBox>(sequence, nearest_sibling);
|
||||
});
|
||||
|
|
|
@ -28,8 +28,11 @@ private:
|
|||
void push_parent(Layout::NodeWithStyle& node) { m_parent_stack.append(&node); }
|
||||
void pop_parent() { m_parent_stack.take_last(); }
|
||||
|
||||
template<CSS::Display, typename Callback>
|
||||
void for_each_in_tree_with_display(NodeWithStyle& root, Callback);
|
||||
template<CSS::Display::Internal, typename Callback>
|
||||
void for_each_in_tree_with_internal_display(NodeWithStyle& root, Callback);
|
||||
|
||||
template<CSS::Display::Inside, typename Callback>
|
||||
void for_each_in_tree_with_inside_display(NodeWithStyle& root, Callback);
|
||||
|
||||
void fixup_tables(NodeWithStyle& root);
|
||||
void remove_irrelevant_boxes(NodeWithStyle& root);
|
||||
|
|
|
@ -19,7 +19,7 @@ SVGGElement::SVGGElement(DOM::Document& document, QualifiedName qualified_name)
|
|||
RefPtr<Layout::Node> SVGGElement::create_layout_node()
|
||||
{
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
return adopt_ref(*new Layout::SVGGraphicsBox(document(), *this, move(style)));
|
||||
}
|
||||
|
|
|
@ -446,7 +446,7 @@ SVGPathElement::SVGPathElement(DOM::Document& document, QualifiedName qualified_
|
|||
RefPtr<Layout::Node> SVGPathElement::create_layout_node()
|
||||
{
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
return adopt_ref(*new Layout::SVGPathBox(document(), *this, move(style)));
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ SVGSVGElement::SVGSVGElement(DOM::Document& document, QualifiedName qualified_na
|
|||
RefPtr<Layout::Node> SVGSVGElement::create_layout_node()
|
||||
{
|
||||
auto style = document().style_computer().compute_style(*this);
|
||||
if (style->display() == CSS::Display::None)
|
||||
if (style->display().is_none())
|
||||
return nullptr;
|
||||
return adopt_ref(*new Layout::SVGSVGBox(document(), *this, move(style)));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue