mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 05:37:43 +00:00
LibWeb: Let paintables cache their containing block and absolute rect
The absolute rect of a paintable is somewhat expensive to compute. This is because all coordinates are relative to the nearest containing block, so we have to traverse the containing block chain and apply each offset to get the final rect. Paintables will never move between containing blocks, nor will their absolute rect change. If anything changes, we'll simpl make a new paintable and replace the old one. Take advantage of this by caching the containing block and absolute rect after first access.
This commit is contained in:
parent
a54fdd5212
commit
b14c6eaef3
5 changed files with 22 additions and 9 deletions
|
@ -38,7 +38,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c
|
||||||
auto top_right_border_radius = computed_values().border_top_right_radius();
|
auto top_right_border_radius = computed_values().border_top_right_radius();
|
||||||
auto bottom_right_border_radius = computed_values().border_bottom_right_radius();
|
auto bottom_right_border_radius = computed_values().border_bottom_right_radius();
|
||||||
auto bottom_left_border_radius = computed_values().border_bottom_left_radius();
|
auto bottom_left_border_radius = computed_values().border_bottom_left_radius();
|
||||||
auto containing_block_position_in_absolute_coordinates = layout_node().containing_block()->paint_box()->absolute_position();
|
auto containing_block_position_in_absolute_coordinates = containing_block()->paint_box()->absolute_position();
|
||||||
|
|
||||||
for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) {
|
for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) {
|
||||||
Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
|
Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
|
||||||
|
@ -89,7 +89,7 @@ void InlinePaintable::paint(PaintContext& context, Painting::PaintPhase phase) c
|
||||||
.left = computed_values().border_left(),
|
.left = computed_values().border_left(),
|
||||||
};
|
};
|
||||||
|
|
||||||
auto containing_block_position_in_absolute_coordinates = layout_node().containing_block()->paint_box()->absolute_position();
|
auto containing_block_position_in_absolute_coordinates = containing_block()->paint_box()->absolute_position();
|
||||||
|
|
||||||
for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) {
|
for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) {
|
||||||
Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
|
Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() };
|
||||||
|
@ -132,7 +132,7 @@ void InlinePaintable::for_each_fragment(Callback callback) const
|
||||||
{
|
{
|
||||||
// FIXME: This will be slow if the containing block has a lot of fragments!
|
// FIXME: This will be slow if the containing block has a lot of fragments!
|
||||||
Vector<Layout::LineBoxFragment const&> fragments;
|
Vector<Layout::LineBoxFragment const&> fragments;
|
||||||
layout_node().containing_block()->paint_box()->for_each_fragment([&](auto& fragment) {
|
containing_block()->paint_box()->for_each_fragment([&](auto& fragment) {
|
||||||
if (layout_node().is_inclusive_ancestor_of(fragment.layout_node()))
|
if (layout_node().is_inclusive_ancestor_of(fragment.layout_node()))
|
||||||
fragments.append(fragment);
|
fragments.append(fragment);
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
|
|
|
@ -24,7 +24,7 @@ void Paintable::handle_mousemove(Badge<EventHandler>, Gfx::IntPoint const&, unsi
|
||||||
|
|
||||||
bool Paintable::handle_mousewheel(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned, int wheel_delta_x, int wheel_delta_y)
|
bool Paintable::handle_mousewheel(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned, int wheel_delta_x, int wheel_delta_y)
|
||||||
{
|
{
|
||||||
if (auto* containing_block = layout_node().containing_block()) {
|
if (auto* containing_block = this->containing_block()) {
|
||||||
if (!containing_block->is_scrollable())
|
if (!containing_block->is_scrollable())
|
||||||
return false;
|
return false;
|
||||||
auto new_offset = containing_block->scroll_offset();
|
auto new_offset = containing_block->scroll_offset();
|
||||||
|
|
|
@ -68,6 +68,13 @@ public:
|
||||||
|
|
||||||
void set_needs_display() const { const_cast<Layout::Node&>(m_layout_node).set_needs_display(); }
|
void set_needs_display() const { const_cast<Layout::Node&>(m_layout_node).set_needs_display(); }
|
||||||
|
|
||||||
|
Layout::BlockContainer const* containing_block() const
|
||||||
|
{
|
||||||
|
if (!m_containing_block.has_value())
|
||||||
|
m_containing_block = const_cast<Layout::Node&>(m_layout_node).containing_block();
|
||||||
|
return *m_containing_block;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Paintable(Layout::Node const& layout_node)
|
explicit Paintable(Layout::Node const& layout_node)
|
||||||
: m_layout_node(layout_node)
|
: m_layout_node(layout_node)
|
||||||
|
@ -76,6 +83,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Layout::Node const& m_layout_node;
|
Layout::Node const& m_layout_node;
|
||||||
|
Optional<Layout::BlockContainer*> mutable m_containing_block;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ void PaintableBox::set_content_size(Gfx::FloatSize const& size)
|
||||||
Gfx::FloatPoint PaintableBox::effective_offset() const
|
Gfx::FloatPoint PaintableBox::effective_offset() const
|
||||||
{
|
{
|
||||||
if (m_containing_line_box_fragment.has_value()) {
|
if (m_containing_line_box_fragment.has_value()) {
|
||||||
auto const& fragment = layout_box().containing_block()->paint_box()->line_boxes()[m_containing_line_box_fragment->line_box_index].fragments()[m_containing_line_box_fragment->fragment_index];
|
auto const& fragment = containing_block()->paint_box()->line_boxes()[m_containing_line_box_fragment->line_box_index].fragments()[m_containing_line_box_fragment->fragment_index];
|
||||||
return fragment.offset();
|
return fragment.offset();
|
||||||
}
|
}
|
||||||
return m_offset;
|
return m_offset;
|
||||||
|
@ -66,10 +66,13 @@ Gfx::FloatPoint PaintableBox::effective_offset() const
|
||||||
|
|
||||||
Gfx::FloatRect PaintableBox::absolute_rect() const
|
Gfx::FloatRect PaintableBox::absolute_rect() const
|
||||||
{
|
{
|
||||||
Gfx::FloatRect rect { effective_offset(), content_size() };
|
if (!m_absolute_rect.has_value()) {
|
||||||
for (auto* block = layout_box().containing_block(); block; block = block->containing_block())
|
Gfx::FloatRect rect { effective_offset(), content_size() };
|
||||||
rect.translate_by(block->paint_box()->effective_offset());
|
for (auto const* block = containing_block(); block && block->paintable(); block = block->paintable()->containing_block())
|
||||||
return rect;
|
rect.translate_by(block->paint_box()->effective_offset());
|
||||||
|
m_absolute_rect = rect;
|
||||||
|
}
|
||||||
|
return *m_absolute_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaintableBox::set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate> fragment_coordinate)
|
void PaintableBox::set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate> fragment_coordinate)
|
||||||
|
|
|
@ -131,6 +131,8 @@ private:
|
||||||
Painting::BorderRadiusData normalized_border_radius_data() const;
|
Painting::BorderRadiusData normalized_border_radius_data() const;
|
||||||
|
|
||||||
OwnPtr<Painting::StackingContext> m_stacking_context;
|
OwnPtr<Painting::StackingContext> m_stacking_context;
|
||||||
|
|
||||||
|
Optional<Gfx::FloatRect> mutable m_absolute_rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PaintableWithLines : public PaintableBox {
|
class PaintableWithLines : public PaintableBox {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue