LibWeb: Verify that save/restore are balanced within paintable

Unbalanced save/restore within display list items recorded for a
paintable means that some state only relevant for the paintable leaks to
subsequent paintables, which is never expected behavior.
This commit is contained in:
Aliaksandr Kalenik 2025-07-06 18:07:43 +02:00 committed by Alexander Kalenik
commit 3dffd71695
Notes: github-actions[bot] 2025-07-06 17:22:32 +00:00
3 changed files with 15 additions and 3 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
* Copyright (c) 2023-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -275,16 +275,19 @@ void DisplayListRecorder::translate(Gfx::IntPoint delta)
void DisplayListRecorder::save()
{
++m_save_nesting_level;
append(Save {});
}
void DisplayListRecorder::save_layer()
{
++m_save_nesting_level;
append(SaveLayer {});
}
void DisplayListRecorder::restore()
{
--m_save_nesting_level;
append(Restore {});
}
@ -419,6 +422,8 @@ void DisplayListRecorder::apply_opacity(float opacity)
void DisplayListRecorder::apply_compositing_and_blending_operator(Gfx::CompositingAndBlendingOperator compositing_and_blending_operator)
{
// Implementation of this item does saveLayer(), so we need to increment the nesting level.
m_save_nesting_level++;
append(ApplyCompositeAndBlendingOperator { .compositing_and_blending_operator = compositing_and_blending_operator });
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
* Copyright (c) 2023-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -161,6 +161,8 @@ public:
void append(Command&& command);
int m_save_nesting_level { 0 };
private:
Vector<Optional<i32>> m_scroll_frame_id_stack;
DisplayList& m_command_list;

View file

@ -1,13 +1,14 @@
/*
* 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>
* Copyright (c) 2024-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/QuickSort.h>
#include <AK/TemporaryChange.h>
#include <LibGfx/AffineTransform.h>
#include <LibGfx/Matrix4x4.h>
#include <LibGfx/Rect.h>
@ -24,9 +25,13 @@ namespace Web::Painting {
static void paint_node(Paintable const& paintable, PaintContext& context, PaintPhase phase)
{
TemporaryChange save_nesting_level(context.display_list_recorder().m_save_nesting_level, 0);
paintable.before_paint(context, phase);
paintable.paint(context, phase);
paintable.after_paint(context, phase);
VERIFY(context.display_list_recorder().m_save_nesting_level == 0);
}
StackingContext::StackingContext(PaintableBox& paintable, StackingContext* parent, size_t index_in_tree_order)