瀏覽代碼

LibWeb: Verify in runtime that stacking context is not painted twice

Duplicated stacking context painting is easy to introduce because of
a bit complicated traversal order and very painful to debug.
Aliaksandr Kalenik 1 年之前
父節點
當前提交
9275743626

+ 3 - 0
Userland/Libraries/LibWeb/Painting/PaintContext.cpp

@@ -9,10 +9,13 @@
 
 namespace Web {
 
+static u64 s_next_paint_generation_id = 0;
+
 PaintContext::PaintContext(Painting::RecordingPainter& recording_painter, Palette const& palette, double device_pixels_per_css_pixel)
     : m_recording_painter(recording_painter)
     , m_palette(palette)
     , m_device_pixels_per_css_pixel(device_pixels_per_css_pixel)
+    , m_paint_generation_id(s_next_paint_generation_id++)
 {
 }
 

+ 3 - 0
Userland/Libraries/LibWeb/Painting/PaintContext.h

@@ -84,6 +84,8 @@ public:
 
     u32 allocate_corner_clipper_id() { return m_next_corner_clipper_id++; }
 
+    u64 paint_generation_id() const { return m_paint_generation_id; }
+
 private:
     Painting::RecordingPainter& m_recording_painter;
     Palette m_palette;
@@ -95,6 +97,7 @@ private:
     bool m_draw_svg_geometry_for_clip_path { false };
     Gfx::AffineTransform m_svg_transform;
     u32 m_next_corner_clipper_id { 0 };
+    u64 m_paint_generation_id { 0 };
 };
 
 }

+ 8 - 0
Userland/Libraries/LibWeb/Painting/StackingContext.cpp

@@ -55,6 +55,12 @@ void StackingContext::sort()
         child->sort();
 }
 
+void StackingContext::set_last_paint_generation_id(u64 generation_id)
+{
+    VERIFY(!m_last_paint_generation_id.has_value() || m_last_paint_generation_id.value() < generation_id);
+    m_last_paint_generation_id = generation_id;
+}
+
 static PaintPhase to_paint_phase(StackingContext::StackingContextPaintPhase phase)
 {
     // There are not a fully correct mapping since some stacking context phases are combined.
@@ -170,6 +176,8 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
 
 void StackingContext::paint_child(PaintContext& context, StackingContext const& child)
 {
+    const_cast<StackingContext&>(child).set_last_paint_generation_id(context.paint_generation_id());
+
     auto parent_paintable = child.paintable().parent();
     if (parent_paintable)
         parent_paintable->before_children_paint(context, PaintPhase::Foreground);

+ 3 - 0
Userland/Libraries/LibWeb/Painting/StackingContext.h

@@ -46,11 +46,14 @@ public:
 
     void sort();
 
+    void set_last_paint_generation_id(u64 generation_id);
+
 private:
     JS::NonnullGCPtr<Paintable> 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<JS::NonnullGCPtr<Paintable const>> m_positioned_descendants_with_stack_level_0_and_stacking_contexts;
     Vector<JS::NonnullGCPtr<Paintable const>> m_non_positioned_floating_descendants;