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
parent 43ef3dc0ab
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);
InlineFormattingContext context(m_state, block_container, *this);
InlineFormattingContext context(m_state, block_container, block_container_state, *this);
context.run(
block_container,
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
*/
@ -18,9 +18,13 @@
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)
, 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
{
// 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;
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;
@ -55,7 +59,7 @@ CSSPixels InlineFormattingContext::leftmost_x_offset_at(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()) {
return AvailableSize::make_definite(m_available_space->width.to_px_or_zero() - (intrusions.left + intrusions.right));
} else {
@ -81,7 +85,7 @@ void InlineFormattingContext::run(Box const&, LayoutMode layout_mode, AvailableS
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();
}
@ -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.
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));
@ -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.
parent().compute_height(box, AvailableSpace(AvailableSize::make_indefinite(), AvailableSize::make_indefinite()));
} 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);
}
@ -242,12 +246,11 @@ void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify
void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
{
auto& containing_block_state = m_state.get_mutable(containing_block());
auto& line_boxes = containing_block_state.line_boxes;
auto& line_boxes = m_containing_block_used_values.line_boxes;
line_boxes.clear_with_capacity();
InlineLevelIterator iterator(*this, m_state, containing_block(), layout_mode);
LineBuilder line_builder(*this, m_state);
InlineLevelIterator iterator(*this, m_state, containing_block(), m_containing_block_used_values, layout_mode);
LineBuilder line_builder(*this, m_state, m_containing_block_used_values);
// 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
@ -371,7 +374,7 @@ void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode)
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;
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;
@ -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
{
auto top_intrusions = parent().intrusion_by_floats_into_box(m_containing_block_state, y);
auto bottom_intrusions = parent().intrusion_by_floats_into_box(m_containing_block_state, y + containing_block().computed_values().line_height() - 1);
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_used_values, y + containing_block().computed_values().line_height() - 1);
auto left_edge = [](auto& space) -> CSSPixels {
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
*/
@ -15,7 +15,7 @@ namespace Web::Layout {
class InlineFormattingContext final : public FormattingContext {
public:
InlineFormattingContext(LayoutState&, BlockContainer const& containing_block, BlockFormattingContext& parent);
InlineFormattingContext(LayoutState&, BlockContainer const& containing_block, LayoutState::UsedValues& containing_block_used_values, BlockFormattingContext& parent);
~InlineFormattingContext();
BlockFormattingContext& parent();
@ -41,7 +41,7 @@ private:
void generate_line_boxes(LayoutMode);
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;

View file

@ -13,12 +13,12 @@
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_layout_state(layout_state)
, m_container(container)
, m_container_state(layout_state.get(container))
, m_next_node(container.first_child())
, m_containing_block(containing_block)
, m_containing_block_used_values(containing_block_used_values)
, m_next_node(containing_block.first_child())
, m_layout_mode(layout_mode)
{
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 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.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->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 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.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->border += used_values.border_right;
@ -107,7 +107,7 @@ void InlineLevelIterator::compute_next()
if (m_next_node == nullptr)
return;
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)));
}

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();
CSSPixels next_non_whitespace_sequence_width();
@ -71,8 +71,8 @@ private:
Layout::InlineFormattingContext& m_inline_formatting_context;
Layout::LayoutState& m_layout_state;
JS::NonnullGCPtr<Layout::BlockContainer const> m_container;
Layout::LayoutState::UsedValues const& m_container_state;
JS::NonnullGCPtr<BlockContainer const> m_containing_block;
LayoutState::UsedValues const& m_containing_block_used_values;
JS::GCPtr<Layout::Node const> m_current_node;
JS::GCPtr<Layout::Node const> m_next_node;
LayoutMode const m_layout_mode;

View file

@ -10,12 +10,12 @@
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_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);
}
@ -35,7 +35,7 @@ void LineBuilder::break_line(ForcedBreak forced_break, Optional<CSSPixels> next_
size_t break_count = 0;
bool floats_intrude_at_current_y = false;
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);
break_count++;
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;
// 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;
}
}
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())
line_boxes.append(LineBox {});
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());
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,
};
}
@ -139,7 +139,7 @@ bool LineBuilder::should_break(CSSPixels next_item_width)
if (m_available_width_for_current_line.is_max_content())
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 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.
@ -155,7 +155,7 @@ bool LineBuilder::should_break(CSSPixels next_item_width)
void LineBuilder::update_last_line()
{
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())
return;
@ -330,7 +330,7 @@ void LineBuilder::update_last_line()
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.
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()) {
line_boxes.take_last();
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_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);
if (!m_containing_block_state.line_boxes.is_empty())
m_containing_block_state.line_boxes.last().m_original_available_width = m_available_width_for_current_line;
if (!m_containing_block_used_values.line_boxes.is_empty())
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);
public:
LineBuilder(InlineFormattingContext&, LayoutState&);
LineBuilder(InlineFormattingContext&, LayoutState&, LayoutState::UsedValues& containing_block_used_values);
~LineBuilder();
enum class ForcedBreak {
@ -58,7 +58,7 @@ private:
InlineFormattingContext& m_context;
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() };
CSSPixels m_current_y { 0 };
CSSPixels m_max_height_on_current_line { 0 };