LibWeb: Use cached UsedValues pointer in IFC and its helper classes

This avoids expensive LayoutState lookups when we already have the
pointer sitting around anyway.
This commit is contained in:
Andreas Kling 2024-03-15 19:25:00 +01:00
commit 1cea4e6407
Notes: sideshowbarker 2024-07-16 21:39:23 +09:00
7 changed files with 48 additions and 45 deletions

View file

@ -472,7 +472,7 @@ void BlockFormattingContext::layout_inline_children(BlockContainer const& block_
auto& block_container_state = m_state.get_mutable(block_container); auto& block_container_state = m_state.get_mutable(block_container);
InlineFormattingContext context(m_state, block_container, *this); InlineFormattingContext context(m_state, block_container, block_container_state, *this);
context.run( context.run(
block_container, block_container,
layout_mode, layout_mode,

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org> * Copyright (c) 2020-2024, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -18,9 +18,13 @@
namespace Web::Layout { namespace Web::Layout {
InlineFormattingContext::InlineFormattingContext(LayoutState& state, BlockContainer const& containing_block, BlockFormattingContext& parent) InlineFormattingContext::InlineFormattingContext(
LayoutState& state,
BlockContainer const& containing_block,
LayoutState::UsedValues& containing_block_used_values,
BlockFormattingContext& parent)
: FormattingContext(Type::Inline, state, containing_block, &parent) : FormattingContext(Type::Inline, state, containing_block, &parent)
, m_containing_block_state(state.get(containing_block)) , m_containing_block_used_values(containing_block_used_values)
{ {
} }
@ -39,7 +43,7 @@ BlockFormattingContext const& InlineFormattingContext::parent() const
CSSPixels InlineFormattingContext::leftmost_x_offset_at(CSSPixels y) const CSSPixels InlineFormattingContext::leftmost_x_offset_at(CSSPixels y) const
{ {
// NOTE: Floats are relative to the BFC root box, not necessarily the containing block of this IFC. // NOTE: Floats are relative to the BFC root box, not necessarily the containing block of this IFC.
auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(m_containing_block_state, parent().root()); auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(m_containing_block_used_values, parent().root());
CSSPixels y_in_root = box_in_root_rect.y() + y; CSSPixels y_in_root = box_in_root_rect.y() + y;
auto space_and_containing_margin = parent().space_used_and_containing_margin_for_floats(y_in_root); auto space_and_containing_margin = parent().space_used_and_containing_margin_for_floats(y_in_root);
auto left_side_floats_limit_to_right = space_and_containing_margin.left_total_containing_margin + space_and_containing_margin.left_used_space; auto left_side_floats_limit_to_right = space_and_containing_margin.left_total_containing_margin + space_and_containing_margin.left_used_space;
@ -55,7 +59,7 @@ CSSPixels InlineFormattingContext::leftmost_x_offset_at(CSSPixels y) const
AvailableSize InlineFormattingContext::available_space_for_line(CSSPixels y) const AvailableSize InlineFormattingContext::available_space_for_line(CSSPixels y) const
{ {
auto intrusions = parent().intrusion_by_floats_into_box(m_containing_block_state, y); auto intrusions = parent().intrusion_by_floats_into_box(m_containing_block_used_values, y);
if (m_available_space->width.is_definite()) { if (m_available_space->width.is_definite()) {
return AvailableSize::make_definite(m_available_space->width.to_px_or_zero() - (intrusions.left + intrusions.right)); return AvailableSize::make_definite(m_available_space->width.to_px_or_zero() - (intrusions.left + intrusions.right));
} else { } else {
@ -81,7 +85,7 @@ void InlineFormattingContext::run(Box const&, LayoutMode layout_mode, AvailableS
CSSPixels content_height = 0; CSSPixels content_height = 0;
for (auto& line_box : m_containing_block_state.line_boxes) { for (auto& line_box : m_containing_block_used_values.line_boxes) {
content_height += line_box.height(); content_height += line_box.height();
} }
@ -174,7 +178,7 @@ void InlineFormattingContext::dimension_box_on_line(Box const& box, LayoutMode l
// NOTE: Flex containers with `auto` height are treated as `max-content`, so we can compute their height early. // NOTE: Flex containers with `auto` height are treated as `max-content`, so we can compute their height early.
if (box_state.has_definite_height() || box.display().is_flex_inside()) if (box_state.has_definite_height() || box.display().is_flex_inside())
parent().compute_height(box, AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_definite(m_containing_block_state.content_height()))); parent().compute_height(box, AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_definite(m_containing_block_used_values.content_height())));
auto independent_formatting_context = layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space)); auto independent_formatting_context = layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space));
@ -183,7 +187,7 @@ void InlineFormattingContext::dimension_box_on_line(Box const& box, LayoutMode l
// FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7. // FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7.
parent().compute_height(box, AvailableSpace(AvailableSize::make_indefinite(), AvailableSize::make_indefinite())); parent().compute_height(box, AvailableSpace(AvailableSize::make_indefinite(), AvailableSize::make_indefinite()));
} else { } else {
auto inner_height = calculate_inner_height(box, AvailableSize::make_definite(m_containing_block_state.content_height()), height_value); auto inner_height = calculate_inner_height(box, AvailableSize::make_definite(m_containing_block_used_values.content_height()), height_value);
box_state.set_content_height(inner_height); box_state.set_content_height(inner_height);
} }
@ -242,12 +246,11 @@ void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify
void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode) void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
{ {
auto& containing_block_state = m_state.get_mutable(containing_block()); auto& line_boxes = m_containing_block_used_values.line_boxes;
auto& line_boxes = containing_block_state.line_boxes;
line_boxes.clear_with_capacity(); line_boxes.clear_with_capacity();
InlineLevelIterator iterator(*this, m_state, containing_block(), layout_mode); InlineLevelIterator iterator(*this, m_state, containing_block(), m_containing_block_used_values, layout_mode);
LineBuilder line_builder(*this, m_state); LineBuilder line_builder(*this, m_state, m_containing_block_used_values);
// NOTE: When we ignore collapsible whitespace chunks at the start of a line, // NOTE: When we ignore collapsible whitespace chunks at the start of a line,
// we have to remember how much start margin that chunk had in the inline // we have to remember how much start margin that chunk had in the inline
@ -371,7 +374,7 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
bool InlineFormattingContext::any_floats_intrude_at_y(CSSPixels y) const bool InlineFormattingContext::any_floats_intrude_at_y(CSSPixels y) const
{ {
auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(m_containing_block_state, parent().root()); auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(m_containing_block_used_values, parent().root());
CSSPixels y_in_root = box_in_root_rect.y() + y; CSSPixels y_in_root = box_in_root_rect.y() + y;
auto space_and_containing_margin = parent().space_used_and_containing_margin_for_floats(y_in_root); auto space_and_containing_margin = parent().space_used_and_containing_margin_for_floats(y_in_root);
return space_and_containing_margin.left_used_space > 0 || space_and_containing_margin.right_used_space > 0; return space_and_containing_margin.left_used_space > 0 || space_and_containing_margin.right_used_space > 0;
@ -379,8 +382,8 @@ bool InlineFormattingContext::any_floats_intrude_at_y(CSSPixels y) const
bool InlineFormattingContext::can_fit_new_line_at_y(CSSPixels y) const bool InlineFormattingContext::can_fit_new_line_at_y(CSSPixels y) const
{ {
auto top_intrusions = parent().intrusion_by_floats_into_box(m_containing_block_state, y); auto top_intrusions = parent().intrusion_by_floats_into_box(m_containing_block_used_values, y);
auto bottom_intrusions = parent().intrusion_by_floats_into_box(m_containing_block_state, y + containing_block().computed_values().line_height() - 1); auto bottom_intrusions = parent().intrusion_by_floats_into_box(m_containing_block_used_values, y + containing_block().computed_values().line_height() - 1);
auto left_edge = [](auto& space) -> CSSPixels { auto left_edge = [](auto& space) -> CSSPixels {
return space.left; return space.left;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org> * Copyright (c) 2020-2024, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -15,7 +15,7 @@ namespace Web::Layout {
class InlineFormattingContext final : public FormattingContext { class InlineFormattingContext final : public FormattingContext {
public: public:
InlineFormattingContext(LayoutState&, BlockContainer const& containing_block, BlockFormattingContext& parent); InlineFormattingContext(LayoutState&, BlockContainer const& containing_block, LayoutState::UsedValues& containing_block_used_values, BlockFormattingContext& parent);
~InlineFormattingContext(); ~InlineFormattingContext();
BlockFormattingContext& parent(); BlockFormattingContext& parent();
@ -41,7 +41,7 @@ private:
void generate_line_boxes(LayoutMode); void generate_line_boxes(LayoutMode);
void apply_justification_to_fragments(CSS::TextJustify, LineBox&, bool is_last_line); void apply_justification_to_fragments(CSS::TextJustify, LineBox&, bool is_last_line);
LayoutState::UsedValues const& m_containing_block_state; LayoutState::UsedValues& m_containing_block_used_values;
Optional<AvailableSpace> m_available_space; Optional<AvailableSpace> m_available_space;

View file

@ -13,12 +13,12 @@
namespace Web::Layout { namespace Web::Layout {
InlineLevelIterator::InlineLevelIterator(Layout::InlineFormattingContext& inline_formatting_context, Layout::LayoutState& layout_state, Layout::BlockContainer const& container, LayoutMode layout_mode) InlineLevelIterator::InlineLevelIterator(Layout::InlineFormattingContext& inline_formatting_context, Layout::LayoutState& layout_state, Layout::BlockContainer const& containing_block, LayoutState::UsedValues const& containing_block_used_values, LayoutMode layout_mode)
: m_inline_formatting_context(inline_formatting_context) : m_inline_formatting_context(inline_formatting_context)
, m_layout_state(layout_state) , m_layout_state(layout_state)
, m_container(container) , m_containing_block(containing_block)
, m_container_state(layout_state.get(container)) , m_containing_block_used_values(containing_block_used_values)
, m_next_node(container.first_child()) , m_next_node(containing_block.first_child())
, m_layout_mode(layout_mode) , m_layout_mode(layout_mode)
{ {
skip_to_next(); skip_to_next();
@ -34,9 +34,9 @@ void InlineLevelIterator::enter_node_with_box_model_metrics(Layout::NodeWithStyl
auto& used_values = m_layout_state.get_mutable(node); auto& used_values = m_layout_state.get_mutable(node);
auto const& computed_values = node.computed_values(); auto const& computed_values = node.computed_values();
used_values.margin_left = computed_values.margin().left().to_px(node, m_container_state.content_width()); used_values.margin_left = computed_values.margin().left().to_px(node, m_containing_block_used_values.content_width());
used_values.border_left = computed_values.border_left().width; used_values.border_left = computed_values.border_left().width;
used_values.padding_left = computed_values.padding().left().to_px(node, m_container_state.content_width()); used_values.padding_left = computed_values.padding().left().to_px(node, m_containing_block_used_values.content_width());
m_extra_leading_metrics->margin += used_values.margin_left; m_extra_leading_metrics->margin += used_values.margin_left;
m_extra_leading_metrics->border += used_values.border_left; m_extra_leading_metrics->border += used_values.border_left;
@ -57,9 +57,9 @@ void InlineLevelIterator::exit_node_with_box_model_metrics()
auto& used_values = m_layout_state.get_mutable(node); auto& used_values = m_layout_state.get_mutable(node);
auto const& computed_values = node->computed_values(); auto const& computed_values = node->computed_values();
used_values.margin_right = computed_values.margin().right().to_px(node, m_container_state.content_width()); used_values.margin_right = computed_values.margin().right().to_px(node, m_containing_block_used_values.content_width());
used_values.border_right = computed_values.border_right().width; used_values.border_right = computed_values.border_right().width;
used_values.padding_right = computed_values.padding().right().to_px(node, m_container_state.content_width()); used_values.padding_right = computed_values.padding().right().to_px(node, m_containing_block_used_values.content_width());
m_extra_trailing_metrics->margin += used_values.margin_right; m_extra_trailing_metrics->margin += used_values.margin_right;
m_extra_trailing_metrics->border += used_values.border_right; m_extra_trailing_metrics->border += used_values.border_right;
@ -107,7 +107,7 @@ void InlineLevelIterator::compute_next()
if (m_next_node == nullptr) if (m_next_node == nullptr)
return; return;
do { do {
m_next_node = next_inline_node_in_pre_order(*m_next_node, m_container); m_next_node = next_inline_node_in_pre_order(*m_next_node, m_containing_block);
} while (m_next_node && (!m_next_node->is_inline() && !m_next_node->is_out_of_flow(m_inline_formatting_context))); } while (m_next_node && (!m_next_node->is_inline() && !m_next_node->is_out_of_flow(m_inline_formatting_context)));
} }

View file

@ -50,7 +50,7 @@ public:
} }
}; };
InlineLevelIterator(Layout::InlineFormattingContext&, LayoutState&, Layout::BlockContainer const&, LayoutMode); InlineLevelIterator(Layout::InlineFormattingContext&, LayoutState&, Layout::BlockContainer const& containing_block, LayoutState::UsedValues const& containing_block_used_values, LayoutMode);
Optional<Item> next(); Optional<Item> next();
CSSPixels next_non_whitespace_sequence_width(); CSSPixels next_non_whitespace_sequence_width();
@ -71,8 +71,8 @@ private:
Layout::InlineFormattingContext& m_inline_formatting_context; Layout::InlineFormattingContext& m_inline_formatting_context;
Layout::LayoutState& m_layout_state; Layout::LayoutState& m_layout_state;
JS::NonnullGCPtr<Layout::BlockContainer const> m_container; JS::NonnullGCPtr<BlockContainer const> m_containing_block;
Layout::LayoutState::UsedValues const& m_container_state; LayoutState::UsedValues const& m_containing_block_used_values;
JS::GCPtr<Layout::Node const> m_current_node; JS::GCPtr<Layout::Node const> m_current_node;
JS::GCPtr<Layout::Node const> m_next_node; JS::GCPtr<Layout::Node const> m_next_node;
LayoutMode const m_layout_mode; LayoutMode const m_layout_mode;

View file

@ -10,12 +10,12 @@
namespace Web::Layout { namespace Web::Layout {
LineBuilder::LineBuilder(InlineFormattingContext& context, LayoutState& layout_state) LineBuilder::LineBuilder(InlineFormattingContext& context, LayoutState& layout_state, LayoutState::UsedValues& containing_block_used_values)
: m_context(context) : m_context(context)
, m_layout_state(layout_state) , m_layout_state(layout_state)
, m_containing_block_state(layout_state.get_mutable(context.containing_block())) , m_containing_block_used_values(containing_block_used_values)
{ {
m_text_indent = m_context.containing_block().computed_values().text_indent().to_px(m_context.containing_block(), m_containing_block_state.content_width()); m_text_indent = m_context.containing_block().computed_values().text_indent().to_px(m_context.containing_block(), m_containing_block_used_values.content_width());
begin_new_line(false); begin_new_line(false);
} }
@ -35,7 +35,7 @@ void LineBuilder::break_line(ForcedBreak forced_break, Optional<CSSPixels> next_
size_t break_count = 0; size_t break_count = 0;
bool floats_intrude_at_current_y = false; bool floats_intrude_at_current_y = false;
do { do {
m_containing_block_state.line_boxes.append(LineBox()); m_containing_block_used_values.line_boxes.append(LineBox());
begin_new_line(true, break_count == 0); begin_new_line(true, break_count == 0);
break_count++; break_count++;
floats_intrude_at_current_y = m_context.any_floats_intrude_at_y(m_current_y); floats_intrude_at_current_y = m_context.any_floats_intrude_at_y(m_current_y);
@ -71,14 +71,14 @@ void LineBuilder::begin_new_line(bool increment_y, bool is_first_break_in_sequen
m_last_line_needs_update = true; m_last_line_needs_update = true;
// FIXME: Support text-indent with "each-line". // FIXME: Support text-indent with "each-line".
if (m_containing_block_state.line_boxes.size() <= 1) { if (m_containing_block_used_values.line_boxes.size() <= 1) {
ensure_last_line_box().m_width += m_text_indent; ensure_last_line_box().m_width += m_text_indent;
} }
} }
LineBox& LineBuilder::ensure_last_line_box() LineBox& LineBuilder::ensure_last_line_box()
{ {
auto& line_boxes = m_containing_block_state.line_boxes; auto& line_boxes = m_containing_block_used_values.line_boxes;
if (line_boxes.is_empty()) if (line_boxes.is_empty())
line_boxes.append(LineBox {}); line_boxes.append(LineBox {});
return line_boxes.last(); return line_boxes.last();
@ -92,7 +92,7 @@ void LineBuilder::append_box(Box const& box, CSSPixels leading_size, CSSPixels t
m_max_height_on_current_line = max(m_max_height_on_current_line, box_state.margin_box_height()); m_max_height_on_current_line = max(m_max_height_on_current_line, box_state.margin_box_height());
box_state.containing_line_box_fragment = LineBoxFragmentCoordinate { box_state.containing_line_box_fragment = LineBoxFragmentCoordinate {
.line_box_index = m_containing_block_state.line_boxes.size() - 1, .line_box_index = m_containing_block_used_values.line_boxes.size() - 1,
.fragment_index = line_box.fragments().size() - 1, .fragment_index = line_box.fragments().size() - 1,
}; };
} }
@ -139,7 +139,7 @@ bool LineBuilder::should_break(CSSPixels next_item_width)
if (m_available_width_for_current_line.is_max_content()) if (m_available_width_for_current_line.is_max_content())
return false; return false;
auto const& line_boxes = m_containing_block_state.line_boxes; auto const& line_boxes = m_containing_block_used_values.line_boxes;
if (line_boxes.is_empty() || line_boxes.last().is_empty()) { if (line_boxes.is_empty() || line_boxes.last().is_empty()) {
// If we don't have a single line box yet *and* there are no floats intruding // If we don't have a single line box yet *and* there are no floats intruding
// at this Y coordinate, we don't need to break before inserting anything. // at this Y coordinate, we don't need to break before inserting anything.
@ -155,7 +155,7 @@ bool LineBuilder::should_break(CSSPixels next_item_width)
void LineBuilder::update_last_line() void LineBuilder::update_last_line()
{ {
m_last_line_needs_update = false; m_last_line_needs_update = false;
auto& line_boxes = m_containing_block_state.line_boxes; auto& line_boxes = m_containing_block_used_values.line_boxes;
if (line_boxes.is_empty()) if (line_boxes.is_empty())
return; return;
@ -330,7 +330,7 @@ void LineBuilder::update_last_line()
void LineBuilder::remove_last_line_if_empty() void LineBuilder::remove_last_line_if_empty()
{ {
// If there's an empty line box at the bottom, just remove it instead of giving it height. // If there's an empty line box at the bottom, just remove it instead of giving it height.
auto& line_boxes = m_containing_block_state.line_boxes; auto& line_boxes = m_containing_block_used_values.line_boxes;
if (!line_boxes.is_empty() && line_boxes.last().is_empty()) { if (!line_boxes.is_empty() && line_boxes.last().is_empty()) {
line_boxes.take_last(); line_boxes.take_last();
m_last_line_needs_update = false; m_last_line_needs_update = false;
@ -343,8 +343,8 @@ void LineBuilder::recalculate_available_space()
auto available_at_top_of_line_box = m_context.available_space_for_line(m_current_y); auto available_at_top_of_line_box = m_context.available_space_for_line(m_current_y);
auto available_at_bottom_of_line_box = m_context.available_space_for_line(m_current_y + current_line_height - 1); auto available_at_bottom_of_line_box = m_context.available_space_for_line(m_current_y + current_line_height - 1);
m_available_width_for_current_line = min(available_at_bottom_of_line_box, available_at_top_of_line_box); m_available_width_for_current_line = min(available_at_bottom_of_line_box, available_at_top_of_line_box);
if (!m_containing_block_state.line_boxes.is_empty()) if (!m_containing_block_used_values.line_boxes.is_empty())
m_containing_block_state.line_boxes.last().m_original_available_width = m_available_width_for_current_line; m_containing_block_used_values.line_boxes.last().m_original_available_width = m_available_width_for_current_line;
} }
} }

View file

@ -15,7 +15,7 @@ class LineBuilder {
AK_MAKE_NONMOVABLE(LineBuilder); AK_MAKE_NONMOVABLE(LineBuilder);
public: public:
LineBuilder(InlineFormattingContext&, LayoutState&); LineBuilder(InlineFormattingContext&, LayoutState&, LayoutState::UsedValues& containing_block_used_values);
~LineBuilder(); ~LineBuilder();
enum class ForcedBreak { enum class ForcedBreak {
@ -58,7 +58,7 @@ private:
InlineFormattingContext& m_context; InlineFormattingContext& m_context;
LayoutState& m_layout_state; LayoutState& m_layout_state;
LayoutState::UsedValues& m_containing_block_state; LayoutState::UsedValues& m_containing_block_used_values;
AvailableSize m_available_width_for_current_line { AvailableSize::make_indefinite() }; AvailableSize m_available_width_for_current_line { AvailableSize::make_indefinite() };
CSSPixels m_current_y { 0 }; CSSPixels m_current_y { 0 };
CSSPixels m_max_height_on_current_line { 0 }; CSSPixels m_max_height_on_current_line { 0 };