mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-09 09:39:39 +00:00
LibWeb: Allow stacking context to only be created by PaintableBox
For a while we used the wider Paintable type for stacking context, because it was allowed to be created by InlinePaintable and PaintableBox. Now, when InlinePaintable type is gone, we can use more specific PaintableBox type for a stacking context.
This commit is contained in:
parent
ed80e929e5
commit
9f541c363d
Notes:
github-actions[bot]
2024-11-18 19:08:27 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 9f541c363d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2421
7 changed files with 103 additions and 120 deletions
|
@ -128,26 +128,25 @@ TraversalDecision Paintable::hit_test(CSSPixelPoint, HitTestType, Function<Trave
|
|||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
||||
bool Paintable::has_stacking_context() const
|
||||
{
|
||||
if (is_paintable_box())
|
||||
return static_cast<PaintableBox const&>(*this).stacking_context();
|
||||
return false;
|
||||
}
|
||||
|
||||
StackingContext* Paintable::enclosing_stacking_context()
|
||||
{
|
||||
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
|
||||
if (auto* stacking_context = ancestor->stacking_context())
|
||||
if (!ancestor->is_paintable_box())
|
||||
continue;
|
||||
if (auto* stacking_context = static_cast<PaintableBox&>(*ancestor).stacking_context())
|
||||
return const_cast<StackingContext*>(stacking_context);
|
||||
}
|
||||
// We should always reach the viewport's stacking context.
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
void Paintable::set_stacking_context(NonnullOwnPtr<StackingContext> stacking_context)
|
||||
{
|
||||
m_stacking_context = move(stacking_context);
|
||||
}
|
||||
|
||||
void Paintable::invalidate_stacking_context()
|
||||
{
|
||||
m_stacking_context = nullptr;
|
||||
}
|
||||
|
||||
void Paintable::set_needs_display(InvalidateDisplayList should_invalidate_display_list)
|
||||
{
|
||||
auto& document = const_cast<DOM::Document&>(this->document());
|
||||
|
|
|
@ -146,13 +146,9 @@ public:
|
|||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
||||
StackingContext* stacking_context() { return m_stacking_context; }
|
||||
StackingContext const* stacking_context() const { return m_stacking_context; }
|
||||
void set_stacking_context(NonnullOwnPtr<StackingContext>);
|
||||
bool has_stacking_context() const;
|
||||
StackingContext* enclosing_stacking_context();
|
||||
|
||||
void invalidate_stacking_context();
|
||||
|
||||
virtual void before_paint(PaintContext&, PaintPhase) const { }
|
||||
virtual void after_paint(PaintContext&, PaintPhase) const { }
|
||||
|
||||
|
@ -251,8 +247,6 @@ private:
|
|||
GC::Ref<Layout::Node const> m_layout_node;
|
||||
Optional<GC::Ptr<PaintableBox>> mutable m_containing_block;
|
||||
|
||||
OwnPtr<StackingContext> m_stacking_context;
|
||||
|
||||
SelectionState m_selection_state { SelectionState::None };
|
||||
|
||||
bool m_positioned : 1 { false };
|
||||
|
|
|
@ -437,6 +437,16 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
|
|||
}
|
||||
}
|
||||
|
||||
void PaintableBox::set_stacking_context(NonnullOwnPtr<StackingContext> stacking_context)
|
||||
{
|
||||
m_stacking_context = move(stacking_context);
|
||||
}
|
||||
|
||||
void PaintableBox::invalidate_stacking_context()
|
||||
{
|
||||
m_stacking_context = nullptr;
|
||||
}
|
||||
|
||||
BordersData PaintableBox::remove_element_kind_from_borders_data(PaintableBox::BordersDataWithElementKind borders_data)
|
||||
{
|
||||
return {
|
||||
|
@ -933,7 +943,7 @@ TraversalDecision PaintableWithLines::hit_test(CSSPixelPoint position, HitTestTy
|
|||
}
|
||||
|
||||
for (auto const& fragment : fragments()) {
|
||||
if (fragment.paintable().stacking_context())
|
||||
if (fragment.paintable().has_stacking_context())
|
||||
continue;
|
||||
auto fragment_absolute_rect = fragment.absolute_rect();
|
||||
if (fragment_absolute_rect.contains(position_adjusted_by_scroll_offset)) {
|
||||
|
|
|
@ -35,6 +35,11 @@ public:
|
|||
|
||||
virtual void paint(PaintContext&, PaintPhase) const override;
|
||||
|
||||
StackingContext* stacking_context() { return m_stacking_context; }
|
||||
StackingContext const* stacking_context() const { return m_stacking_context; }
|
||||
void set_stacking_context(NonnullOwnPtr<StackingContext>);
|
||||
void invalidate_stacking_context();
|
||||
|
||||
virtual Optional<CSSPixelRect> get_masking_area() const;
|
||||
virtual Optional<Gfx::Bitmap::MaskKind> get_mask_type() const { return {}; }
|
||||
virtual RefPtr<Gfx::ImmutableBitmap> calculate_mask(PaintContext&, CSSPixelRect const&) const { return {}; }
|
||||
|
@ -276,6 +281,8 @@ private:
|
|||
virtual DispatchEventOfSameName handle_mouseup(Badge<EventHandler>, CSSPixelPoint, unsigned button, unsigned modifiers) override;
|
||||
virtual DispatchEventOfSameName handle_mousemove(Badge<EventHandler>, CSSPixelPoint, unsigned buttons, unsigned modifiers) override;
|
||||
|
||||
OwnPtr<StackingContext> m_stacking_context;
|
||||
|
||||
Optional<OverflowData> m_overflow_data;
|
||||
|
||||
CSSPixelPoint m_offset;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -27,7 +28,7 @@ static void paint_node(Paintable const& paintable, PaintContext& context, PaintP
|
|||
paintable.after_paint(context, phase);
|
||||
}
|
||||
|
||||
StackingContext::StackingContext(Paintable& paintable, StackingContext* parent, size_t index_in_tree_order)
|
||||
StackingContext::StackingContext(PaintableBox& paintable, StackingContext* parent, size_t index_in_tree_order)
|
||||
: m_paintable(paintable)
|
||||
, m_parent(parent)
|
||||
, m_index_in_tree_order(index_in_tree_order)
|
||||
|
@ -40,8 +41,8 @@ StackingContext::StackingContext(Paintable& paintable, StackingContext* parent,
|
|||
void StackingContext::sort()
|
||||
{
|
||||
quick_sort(m_children, [](auto& a, auto& b) {
|
||||
auto a_z_index = a->paintable().computed_values().z_index().value_or(0);
|
||||
auto b_z_index = b->paintable().computed_values().z_index().value_or(0);
|
||||
auto a_z_index = a->paintable_box().computed_values().z_index().value_or(0);
|
||||
auto b_z_index = b->paintable_box().computed_values().z_index().value_or(0);
|
||||
if (a_z_index == b_z_index)
|
||||
return a->m_index_in_tree_order < b->m_index_in_tree_order;
|
||||
return a_z_index < b_z_index;
|
||||
|
@ -112,7 +113,6 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
|
|||
paintable.before_children_paint(context, to_paint_phase(phase));
|
||||
|
||||
paintable.for_each_child([&context, phase](auto& child) {
|
||||
auto* stacking_context = child.stacking_context();
|
||||
auto const& z_index = child.computed_values().z_index();
|
||||
|
||||
if (child.layout_node().is_svg_svg_box()) {
|
||||
|
@ -120,7 +120,7 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
|
|||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
if (stacking_context)
|
||||
if (child.has_stacking_context())
|
||||
return IterationDecision::Continue;
|
||||
|
||||
// NOTE: Grid specification https://www.w3.org/TR/css-grid-2/#z-order says that grid items should be treated
|
||||
|
@ -185,12 +185,12 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
|
|||
|
||||
void StackingContext::paint_child(PaintContext& context, StackingContext const& child)
|
||||
{
|
||||
VERIFY(!child.paintable().layout_node().is_svg_box());
|
||||
VERIFY(!child.paintable().layout_node().is_svg_svg_box());
|
||||
VERIFY(!child.paintable_box().layout_node().is_svg_box());
|
||||
VERIFY(!child.paintable_box().layout_node().is_svg_svg_box());
|
||||
|
||||
const_cast<StackingContext&>(child).set_last_paint_generation_id(context.paint_generation_id());
|
||||
|
||||
auto parent_paintable = child.paintable().parent();
|
||||
auto parent_paintable = child.paintable_box().parent();
|
||||
if (parent_paintable)
|
||||
parent_paintable->before_children_paint(context, PaintPhase::Foreground);
|
||||
|
||||
|
@ -202,16 +202,16 @@ void StackingContext::paint_child(PaintContext& context, StackingContext const&
|
|||
|
||||
void StackingContext::paint_internal(PaintContext& context) const
|
||||
{
|
||||
VERIFY(!paintable().layout_node().is_svg_box());
|
||||
if (paintable().layout_node().is_svg_svg_box()) {
|
||||
VERIFY(!paintable_box().layout_node().is_svg_box());
|
||||
if (paintable_box().layout_node().is_svg_svg_box()) {
|
||||
paint_svg(context, paintable_box(), PaintPhase::Foreground);
|
||||
return;
|
||||
}
|
||||
|
||||
// For a more elaborate description of the algorithm, see CSS 2.1 Appendix E
|
||||
// Draw the background and borders for the context root (steps 1, 2)
|
||||
paint_node(paintable(), context, PaintPhase::Background);
|
||||
paint_node(paintable(), context, PaintPhase::Border);
|
||||
paint_node(paintable_box(), context, PaintPhase::Background);
|
||||
paint_node(paintable_box(), context, PaintPhase::Border);
|
||||
|
||||
// Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order
|
||||
// (most negative first) then tree order. (step 3)
|
||||
|
@ -219,18 +219,18 @@ void StackingContext::paint_internal(PaintContext& context) const
|
|||
// account for new properties like `transform` and `opacity` that can create stacking contexts.
|
||||
// https://github.com/w3c/csswg-drafts/issues/2717
|
||||
for (auto* child : m_children) {
|
||||
if (child->paintable().computed_values().z_index().has_value() && child->paintable().computed_values().z_index().value() < 0)
|
||||
if (child->paintable_box().computed_values().z_index().has_value() && child->paintable_box().computed_values().z_index().value() < 0)
|
||||
paint_child(context, *child);
|
||||
}
|
||||
|
||||
// Draw the background and borders for block-level children (step 4)
|
||||
paint_descendants(context, paintable(), StackingContextPaintPhase::BackgroundAndBorders);
|
||||
paint_descendants(context, paintable_box(), StackingContextPaintPhase::BackgroundAndBorders);
|
||||
// Draw the non-positioned floats (step 5)
|
||||
paint_descendants(context, paintable(), StackingContextPaintPhase::Floats);
|
||||
paint_descendants(context, paintable_box(), StackingContextPaintPhase::Floats);
|
||||
// Draw inline content, replaced content, etc. (steps 6, 7)
|
||||
paint_descendants(context, paintable(), StackingContextPaintPhase::BackgroundAndBordersForInlineLevelAndReplaced);
|
||||
paint_node(paintable(), context, PaintPhase::Foreground);
|
||||
paint_descendants(context, paintable(), StackingContextPaintPhase::Foreground);
|
||||
paint_descendants(context, paintable_box(), StackingContextPaintPhase::BackgroundAndBordersForInlineLevelAndReplaced);
|
||||
paint_node(paintable_box(), context, PaintPhase::Foreground);
|
||||
paint_descendants(context, paintable_box(), StackingContextPaintPhase::Foreground);
|
||||
|
||||
// Draw positioned descendants with z-index `0` or `auto` in tree order. (step 8)
|
||||
// Here, we treat non-positioned stacking contexts as if they were positioned, because CSS 2.0 spec does not
|
||||
|
@ -257,15 +257,15 @@ void StackingContext::paint_internal(PaintContext& context) const
|
|||
// account for new properties like `transform` and `opacity` that can create stacking contexts.
|
||||
// https://github.com/w3c/csswg-drafts/issues/2717
|
||||
for (auto* child : m_children) {
|
||||
if (child->paintable().computed_values().z_index().has_value() && child->paintable().computed_values().z_index().value() >= 1)
|
||||
if (child->paintable_box().computed_values().z_index().has_value() && child->paintable_box().computed_values().z_index().value() >= 1)
|
||||
paint_child(context, *child);
|
||||
}
|
||||
|
||||
paint_node(paintable(), context, PaintPhase::Outline);
|
||||
paint_node(paintable_box(), context, PaintPhase::Outline);
|
||||
|
||||
if (context.should_paint_overlay()) {
|
||||
paint_node(paintable(), context, PaintPhase::Overlay);
|
||||
paint_descendants(context, paintable(), StackingContextPaintPhase::FocusAndOverlay);
|
||||
paint_node(paintable_box(), context, PaintPhase::Overlay);
|
||||
paint_descendants(context, paintable_box(), StackingContextPaintPhase::FocusAndOverlay);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,9 +273,7 @@ void StackingContext::paint_internal(PaintContext& context) const
|
|||
// Use the whole matrix when we get better transformation support in LibGfx or use LibGL for drawing the bitmap
|
||||
Gfx::AffineTransform StackingContext::affine_transform_matrix() const
|
||||
{
|
||||
if (paintable().is_paintable_box())
|
||||
return Gfx::extract_2d_affine_transform(paintable_box().transform());
|
||||
return Gfx::AffineTransform {};
|
||||
}
|
||||
|
||||
static Gfx::FloatMatrix4x4 matrix_with_scaled_translation(Gfx::FloatMatrix4x4 matrix, float scale)
|
||||
|
@ -289,31 +287,22 @@ static Gfx::FloatMatrix4x4 matrix_with_scaled_translation(Gfx::FloatMatrix4x4 ma
|
|||
|
||||
void StackingContext::paint(PaintContext& context) const
|
||||
{
|
||||
auto opacity = paintable().computed_values().opacity();
|
||||
auto opacity = paintable_box().computed_values().opacity();
|
||||
if (opacity == 0.0f)
|
||||
return;
|
||||
|
||||
DisplayListRecorderStateSaver saver(context.display_list_recorder());
|
||||
|
||||
auto to_device_pixels_scale = float(context.device_pixels_per_css_pixel());
|
||||
Gfx::IntRect source_paintable_rect;
|
||||
if (paintable().is_paintable_box()) {
|
||||
source_paintable_rect = context.enclosing_device_rect(paintable_box().absolute_paint_rect()).to_type<int>();
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
auto source_paintable_rect = context.enclosing_device_rect(paintable_box().absolute_paint_rect()).to_type<int>();
|
||||
|
||||
auto transform_matrix = Gfx::FloatMatrix4x4::identity();
|
||||
Gfx::FloatPoint transform_origin;
|
||||
if (paintable().is_paintable_box()) {
|
||||
transform_matrix = paintable_box().transform();
|
||||
transform_origin = paintable_box().transform_origin().to_type<float>();
|
||||
}
|
||||
auto transform_matrix = paintable_box().transform();
|
||||
auto transform_origin = paintable_box().transform_origin().to_type<float>();
|
||||
|
||||
DisplayListRecorder::PushStackingContextParams push_stacking_context_params {
|
||||
.opacity = opacity,
|
||||
.filter = paintable().computed_values().filter(),
|
||||
.is_fixed_position = paintable().is_fixed_position(),
|
||||
.filter = paintable_box().computed_values().filter(),
|
||||
.is_fixed_position = paintable_box().is_fixed_position(),
|
||||
.source_paintable_rect = source_paintable_rect,
|
||||
.transform = {
|
||||
.origin = transform_origin.scaled(to_device_pixels_scale),
|
||||
|
@ -321,26 +310,25 @@ void StackingContext::paint(PaintContext& context) const
|
|||
},
|
||||
};
|
||||
|
||||
auto const& computed_values = paintable().computed_values();
|
||||
auto const& computed_values = paintable_box().computed_values();
|
||||
if (auto clip_path = computed_values.clip_path(); clip_path.has_value() && clip_path->is_basic_shape()) {
|
||||
auto const& masking_area = paintable_box().get_masking_area();
|
||||
auto const& basic_shape = computed_values.clip_path()->basic_shape();
|
||||
auto path = basic_shape.to_path(*masking_area, paintable().layout_node());
|
||||
auto path = basic_shape.to_path(*masking_area, paintable_box().layout_node());
|
||||
auto device_pixel_scale = context.device_pixels_per_css_pixel();
|
||||
push_stacking_context_params.clip_path = path.copy_transformed(Gfx::AffineTransform {}.set_scale(device_pixel_scale, device_pixel_scale).set_translation(source_paintable_rect.location().to_type<float>()));
|
||||
}
|
||||
|
||||
auto has_css_transform = paintable().is_paintable_box() && paintable_box().has_css_transform();
|
||||
auto has_css_transform = paintable_box().has_css_transform();
|
||||
context.display_list_recorder().save();
|
||||
if (has_css_transform) {
|
||||
paintable_box().apply_clip_overflow_rect(context, PaintPhase::Foreground);
|
||||
}
|
||||
if (paintable().is_paintable_box() && paintable_box().scroll_frame_id().has_value()) {
|
||||
if (paintable_box().scroll_frame_id().has_value()) {
|
||||
context.display_list_recorder().push_scroll_frame_id(*paintable_box().scroll_frame_id());
|
||||
}
|
||||
context.display_list_recorder().push_stacking_context(push_stacking_context_params);
|
||||
|
||||
if (paintable().is_paintable_box()) {
|
||||
if (auto masking_area = paintable_box().get_masking_area(); masking_area.has_value()) {
|
||||
if (masking_area->is_empty())
|
||||
return;
|
||||
|
@ -350,11 +338,10 @@ void StackingContext::paint(PaintContext& context) const
|
|||
context.display_list_recorder().apply_mask_bitmap(masking_area_rect.location(), mask_bitmap.release_nonnull(), *paintable_box().get_mask_type());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paint_internal(context);
|
||||
context.display_list_recorder().pop_stacking_context();
|
||||
if (paintable().is_paintable_box() && paintable_box().scroll_frame_id().has_value()) {
|
||||
if (paintable_box().scroll_frame_id().has_value()) {
|
||||
context.display_list_recorder().pop_scroll_frame_id();
|
||||
}
|
||||
if (has_css_transform)
|
||||
|
@ -364,12 +351,10 @@ void StackingContext::paint(PaintContext& context) const
|
|||
|
||||
TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType type, Function<TraversalDecision(HitTestResult)> const& callback) const
|
||||
{
|
||||
if (!paintable().is_visible())
|
||||
if (!paintable_box().is_visible())
|
||||
return TraversalDecision::Continue;
|
||||
|
||||
CSSPixelPoint transform_origin { 0, 0 };
|
||||
if (paintable().is_paintable_box())
|
||||
transform_origin = paintable_box().transform_origin();
|
||||
CSSPixelPoint transform_origin = paintable_box().transform_origin();
|
||||
// NOTE: This CSSPixels -> Float -> CSSPixels conversion is because we can't AffineTransform::map() a CSSPixelPoint.
|
||||
Gfx::FloatPoint offset_position {
|
||||
(position.x() - transform_origin.x()).to_float(),
|
||||
|
@ -384,7 +369,7 @@ TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType
|
|||
// NOTE: Hit testing follows reverse painting order, that's why the conditions here are reversed.
|
||||
for (ssize_t i = m_children.size() - 1; i >= 0; --i) {
|
||||
auto const& child = *m_children[i];
|
||||
if (child.paintable().computed_values().z_index().value_or(0) <= 0)
|
||||
if (child.paintable_box().computed_values().z_index().value_or(0) <= 0)
|
||||
break;
|
||||
if (child.hit_test(transformed_position, type, callback) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
|
@ -402,9 +387,9 @@ TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType
|
|||
}
|
||||
|
||||
// 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
|
||||
if (paintable().layout_node().children_are_inline() && is<Layout::BlockContainer>(paintable().layout_node())) {
|
||||
for (auto const* child = paintable().last_child(); child; child = child->previous_sibling()) {
|
||||
if (child->is_inline() && !child->is_absolutely_positioned() && !child->stacking_context()) {
|
||||
if (paintable_box().layout_node().children_are_inline() && is<Layout::BlockContainer>(paintable_box().layout_node())) {
|
||||
for (auto const* child = paintable_box().last_child(); child; child = child->previous_sibling()) {
|
||||
if (child->is_inline() && !child->is_absolutely_positioned() && !child->has_stacking_context()) {
|
||||
if (child->hit_test(transformed_position, type, callback) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
}
|
||||
|
@ -418,8 +403,8 @@ TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType
|
|||
}
|
||||
|
||||
// 3. the in-flow, non-inline-level, non-positioned descendants.
|
||||
if (!paintable().layout_node().children_are_inline()) {
|
||||
for (auto const* child = paintable().last_child(); child; child = child->previous_sibling()) {
|
||||
if (!paintable_box().layout_node().children_are_inline()) {
|
||||
for (auto const* child = paintable_box().last_child(); child; child = child->previous_sibling()) {
|
||||
if (!child->is_paintable_box())
|
||||
continue;
|
||||
|
||||
|
@ -435,29 +420,23 @@ TraversalDecision StackingContext::hit_test(CSSPixelPoint position, HitTestType
|
|||
// NOTE: Hit testing follows reverse painting order, that's why the conditions here are reversed.
|
||||
for (ssize_t i = m_children.size() - 1; i >= 0; --i) {
|
||||
auto const& child = *m_children[i];
|
||||
if (child.paintable().computed_values().z_index().value_or(0) >= 0)
|
||||
if (child.paintable_box().computed_values().z_index().value_or(0) >= 0)
|
||||
break;
|
||||
if (child.hit_test(transformed_position, type, callback) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
}
|
||||
|
||||
CSSPixelPoint enclosing_scroll_offset;
|
||||
if (is<PaintableBox>(paintable())) {
|
||||
auto const& paintable_box = static_cast<PaintableBox const&>(paintable());
|
||||
enclosing_scroll_offset = paintable_box.cumulative_offset_of_enclosing_scroll_frame();
|
||||
}
|
||||
CSSPixelPoint enclosing_scroll_offset = paintable_box().cumulative_offset_of_enclosing_scroll_frame();
|
||||
|
||||
auto position_adjusted_by_scroll_offset = transformed_position;
|
||||
position_adjusted_by_scroll_offset.translate_by(-enclosing_scroll_offset);
|
||||
|
||||
// 1. the background and borders of the element forming the stacking context.
|
||||
if (paintable().is_paintable_box()) {
|
||||
if (paintable_box().absolute_border_box_rect().contains(position_adjusted_by_scroll_offset.x(), position_adjusted_by_scroll_offset.y())) {
|
||||
auto hit_test_result = HitTestResult { .paintable = const_cast<PaintableBox&>(paintable_box()) };
|
||||
if (callback(hit_test_result) == TraversalDecision::Break)
|
||||
return TraversalDecision::Break;
|
||||
}
|
||||
}
|
||||
|
||||
return TraversalDecision::Continue;
|
||||
}
|
||||
|
@ -467,16 +446,11 @@ void StackingContext::dump(int indent) const
|
|||
StringBuilder builder;
|
||||
for (int i = 0; i < indent; ++i)
|
||||
builder.append(' ');
|
||||
CSSPixelRect rect;
|
||||
if (paintable().is_paintable_box()) {
|
||||
rect = paintable_box().absolute_rect();
|
||||
} else {
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
builder.appendff("SC for {} {} [children: {}] (z-index: ", paintable().layout_node().debug_description(), rect, m_children.size());
|
||||
CSSPixelRect rect = paintable_box().absolute_rect();
|
||||
builder.appendff("SC for {} {} [children: {}] (z-index: ", paintable_box().layout_node().debug_description(), rect, m_children.size());
|
||||
|
||||
if (paintable().computed_values().z_index().has_value())
|
||||
builder.appendff("{}", paintable().computed_values().z_index().value());
|
||||
if (paintable_box().computed_values().z_index().has_value())
|
||||
builder.appendff("{}", paintable_box().computed_values().z_index().value());
|
||||
else
|
||||
builder.append("auto"sv);
|
||||
builder.append(')');
|
||||
|
|
|
@ -16,13 +16,12 @@ class StackingContext {
|
|||
friend class ViewportPaintable;
|
||||
|
||||
public:
|
||||
StackingContext(Paintable&, StackingContext* parent, size_t index_in_tree_order);
|
||||
StackingContext(PaintableBox&, StackingContext* parent, size_t index_in_tree_order);
|
||||
|
||||
StackingContext* parent() { return m_parent; }
|
||||
StackingContext const* parent() const { return m_parent; }
|
||||
|
||||
Paintable const& paintable() const { return *m_paintable; }
|
||||
PaintableBox const& paintable_box() const { return verify_cast<PaintableBox>(*m_paintable); }
|
||||
PaintableBox const& paintable_box() const { return *m_paintable; }
|
||||
|
||||
enum class StackingContextPaintPhase {
|
||||
BackgroundAndBorders,
|
||||
|
@ -48,14 +47,14 @@ public:
|
|||
void set_last_paint_generation_id(u64 generation_id);
|
||||
|
||||
private:
|
||||
GC::Ref<Paintable> m_paintable;
|
||||
GC::Ref<PaintableBox> m_paintable;
|
||||
StackingContext* const m_parent { nullptr };
|
||||
Vector<StackingContext*> m_children;
|
||||
size_t m_index_in_tree_order { 0 };
|
||||
Optional<u64> m_last_paint_generation_id;
|
||||
|
||||
Vector<GC::Ref<Paintable const>> m_positioned_descendants_and_stacking_contexts_with_stack_level_0;
|
||||
Vector<GC::Ref<Paintable const>> m_non_positioned_floating_descendants;
|
||||
Vector<GC::Ref<PaintableBox const>> m_positioned_descendants_and_stacking_contexts_with_stack_level_0;
|
||||
Vector<GC::Ref<PaintableBox const>> m_non_positioned_floating_descendants;
|
||||
|
||||
static void paint_child(PaintContext&, StackingContext const&);
|
||||
void paint_internal(PaintContext&) const;
|
||||
|
|
|
@ -40,20 +40,20 @@ void ViewportPaintable::build_stacking_context_tree()
|
|||
set_stacking_context(make<StackingContext>(*this, nullptr, 0));
|
||||
|
||||
size_t index_in_tree_order = 1;
|
||||
for_each_in_subtree([&](Paintable const& paintable) {
|
||||
const_cast<Paintable&>(paintable).invalidate_stacking_context();
|
||||
auto* parent_context = const_cast<Paintable&>(paintable).enclosing_stacking_context();
|
||||
auto establishes_stacking_context = paintable.layout_node().establishes_stacking_context();
|
||||
if ((paintable.is_positioned() || establishes_stacking_context) && paintable.computed_values().z_index().value_or(0) == 0)
|
||||
parent_context->m_positioned_descendants_and_stacking_contexts_with_stack_level_0.append(paintable);
|
||||
if (!paintable.is_positioned() && paintable.is_floating())
|
||||
parent_context->m_non_positioned_floating_descendants.append(paintable);
|
||||
for_each_in_subtree_of_type<PaintableBox>([&](auto const& paintable_box) {
|
||||
const_cast<PaintableBox&>(paintable_box).invalidate_stacking_context();
|
||||
auto* parent_context = const_cast<PaintableBox&>(paintable_box).enclosing_stacking_context();
|
||||
auto establishes_stacking_context = paintable_box.layout_node().establishes_stacking_context();
|
||||
if ((paintable_box.is_positioned() || establishes_stacking_context) && paintable_box.computed_values().z_index().value_or(0) == 0)
|
||||
parent_context->m_positioned_descendants_and_stacking_contexts_with_stack_level_0.append(paintable_box);
|
||||
if (!paintable_box.is_positioned() && paintable_box.is_floating())
|
||||
parent_context->m_non_positioned_floating_descendants.append(paintable_box);
|
||||
if (!establishes_stacking_context) {
|
||||
VERIFY(!paintable.stacking_context());
|
||||
VERIFY(!paintable_box.stacking_context());
|
||||
return TraversalDecision::Continue;
|
||||
}
|
||||
VERIFY(parent_context);
|
||||
const_cast<Paintable&>(paintable).set_stacking_context(make<Painting::StackingContext>(const_cast<Paintable&>(paintable), parent_context, index_in_tree_order++));
|
||||
const_cast<PaintableBox&>(paintable_box).set_stacking_context(make<Painting::StackingContext>(const_cast<PaintableBox&>(paintable_box), parent_context, index_in_tree_order++));
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue