mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 07:48:12 +00:00
LibWeb: Improve how layout nodes decide whether they have definite sizes
1. Make this decision *after* we've inserted the layout node into the layout tree. Otherwise, we can't reach its containing block! 2. Per css-sizing-3, consider auto-sized blocks whose sizes resolve solely against other definite sizes as definite themselves. In particular, (2) makes us consider width:auto block children of a definite-size containing block as having definite size. This becomes very important in flex layout.
This commit is contained in:
parent
d201378750
commit
12ac6861e3
3 changed files with 47 additions and 25 deletions
|
@ -179,6 +179,43 @@ NodeWithStyle::NodeWithStyle(DOM::Document& document, DOM::Node* node, CSS::Comp
|
|||
m_font = Gfx::FontDatabase::default_font();
|
||||
}
|
||||
|
||||
void NodeWithStyle::did_insert_into_layout_tree(CSS::StyleProperties const& style)
|
||||
{
|
||||
// https://drafts.csswg.org/css-sizing-3/#definite
|
||||
auto is_definite_size = [&](CSS::PropertyID property_id, bool width) {
|
||||
// A size that can be determined without performing layout; that is,
|
||||
// a <length>,
|
||||
// a measure of text (without consideration of line-wrapping),
|
||||
// a size of the initial containing block,
|
||||
// or a <percentage> or other formula (such as the “stretch-fit” sizing of non-replaced blocks [CSS2]) that is resolved solely against definite sizes.
|
||||
auto maybe_value = style.property(property_id);
|
||||
|
||||
auto const* containing_block = this->containing_block();
|
||||
auto containing_block_has_definite_size = containing_block && (width ? containing_block->m_has_definite_width : containing_block->m_has_definite_height);
|
||||
|
||||
if (!maybe_value.has_value() || maybe_value.value()->has_auto()) {
|
||||
// NOTE: The width of a non-flex-item block is considered definite if it's auto and the containing block has definite width.
|
||||
if (width && is_block_container() && parent() && !parent()->computed_values().display().is_flex_inside())
|
||||
return containing_block_has_definite_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto maybe_length_percentage = style.length_percentage(property_id);
|
||||
if (!maybe_length_percentage.has_value())
|
||||
return false;
|
||||
auto length_percentage = maybe_length_percentage.release_value();
|
||||
if (length_percentage.is_length())
|
||||
return true;
|
||||
if (length_percentage.is_percentage())
|
||||
return containing_block_has_definite_size;
|
||||
// FIXME: Determine if calc() value is definite.
|
||||
return false;
|
||||
};
|
||||
|
||||
m_has_definite_width = is_definite_size(CSS::PropertyID::Width, true);
|
||||
m_has_definite_height = is_definite_size(CSS::PropertyID::Height, false);
|
||||
}
|
||||
|
||||
void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
|
||||
{
|
||||
auto& computed_values = static_cast<CSS::MutableComputedValues&>(m_computed_values);
|
||||
|
@ -436,27 +473,6 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
|
|||
if (computed_values.opacity() == 0)
|
||||
m_visible = false;
|
||||
|
||||
auto is_definite_size = [&](CSS::PropertyID property_id, bool width) {
|
||||
auto maybe_value = specified_style.property(property_id);
|
||||
if (!maybe_value.has_value() || maybe_value.value()->has_auto())
|
||||
return false;
|
||||
auto maybe_length_percentage = specified_style.length_percentage(property_id);
|
||||
if (!maybe_length_percentage.has_value())
|
||||
return false;
|
||||
auto length_percentage = maybe_length_percentage.release_value();
|
||||
if (length_percentage.is_length())
|
||||
return true;
|
||||
if (length_percentage.is_percentage()) {
|
||||
auto* containing_block = this->containing_block();
|
||||
return containing_block && (width ? containing_block->m_has_definite_width : containing_block->m_has_definite_height);
|
||||
}
|
||||
// FIXME: Determine if calc() value is definite.
|
||||
return false;
|
||||
};
|
||||
|
||||
m_has_definite_width = is_definite_size(CSS::PropertyID::Width, true);
|
||||
m_has_definite_height = is_definite_size(CSS::PropertyID::Height, false);
|
||||
|
||||
if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::Width); maybe_length_percentage.has_value())
|
||||
computed_values.set_width(maybe_length_percentage.release_value());
|
||||
if (auto maybe_length_percentage = specified_style.length_percentage(CSS::PropertyID::MinWidth); maybe_length_percentage.has_value())
|
||||
|
|
|
@ -164,6 +164,8 @@ public:
|
|||
void set_has_definite_height(bool b) { m_has_definite_height = b; }
|
||||
void set_has_definite_width(bool b) { m_has_definite_width = b; }
|
||||
|
||||
void did_insert_into_layout_tree(CSS::StyleProperties const&);
|
||||
|
||||
protected:
|
||||
NodeWithStyle(DOM::Document&, DOM::Node*, NonnullRefPtr<CSS::StyleProperties>);
|
||||
NodeWithStyle(DOM::Document&, DOM::Node*, CSS::ComputedValues);
|
||||
|
|
|
@ -96,18 +96,19 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
auto& document = dom_node.document();
|
||||
auto& style_computer = document.style_computer();
|
||||
RefPtr<Layout::Node> layout_node;
|
||||
RefPtr<CSS::StyleProperties> style;
|
||||
|
||||
if (is<DOM::Element>(dom_node)) {
|
||||
auto& element = static_cast<DOM::Element&>(dom_node);
|
||||
element.clear_pseudo_element_nodes({});
|
||||
auto style = style_computer.compute_style(element);
|
||||
style = style_computer.compute_style(element);
|
||||
if (style->display().is_none())
|
||||
return;
|
||||
element.set_specified_css_values(style);
|
||||
layout_node = element.create_layout_node(move(style));
|
||||
layout_node = element.create_layout_node(*style);
|
||||
} else if (is<DOM::Document>(dom_node)) {
|
||||
auto style = style_computer.create_document_style();
|
||||
layout_node = adopt_ref(*new Layout::InitialContainingBlock(static_cast<DOM::Document&>(dom_node), move(style)));
|
||||
style = style_computer.create_document_style();
|
||||
layout_node = adopt_ref(*new Layout::InitialContainingBlock(static_cast<DOM::Document&>(dom_node), *style));
|
||||
} else if (is<DOM::Text>(dom_node)) {
|
||||
layout_node = adopt_ref(*new Layout::TextNode(document, static_cast<DOM::Text&>(dom_node)));
|
||||
} else if (is<DOM::ShadowRoot>(dom_node)) {
|
||||
|
@ -150,6 +151,9 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
insert_node_into_inline_or_block_ancestor(layout_node);
|
||||
}
|
||||
|
||||
if (layout_node->has_style() && style)
|
||||
static_cast<Layout::NodeWithStyle&>(*layout_node).did_insert_into_layout_tree(*style);
|
||||
|
||||
auto* shadow_root = is<DOM::Element>(dom_node) ? verify_cast<DOM::Element>(dom_node).shadow_root() : nullptr;
|
||||
|
||||
if ((dom_node.has_children() || shadow_root) && layout_node->can_have_children()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue