Fix PaintRenderingContext2D overdraw optimization
The WillOverwriteCanvas method was clearing recording but wasn't
restoring the matrix clip stack.
Bug: 1484741
Change-Id: I2826defce26ef9ac8b66acb6e04ad0461b1d82bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4943674
Commit-Queue: Jean-Philippe Gravel <jpgravel@chromium.org>
Reviewed-by: Aaron Krajeski <aaronhk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1226344}
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
index 8b03df48..00ab643 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d.cc
@@ -112,7 +112,10 @@
if (did_record_draw_commands_in_paint_recorder_) {
// Discard previous draw commands
paint_recorder_.finishRecordingAsPicture();
- InitializePaintRecorder();
+
+ cc::PaintCanvas* canvas = paint_recorder_.beginRecording(container_size_);
+ RestoreMatrixClipStack(canvas);
+ did_record_draw_commands_in_paint_recorder_ = false;
}
}
diff --git a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d_test.cc
index ed84a69..86a056b 100644
--- a/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d_test.cc
+++ b/third_party/blink/renderer/modules/csspaint/paint_rendering_context_2d_test.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_style_test_utils.h"
#include "third_party/blink/renderer/modules/canvas/canvas2d/recording_test_utils.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
namespace {
@@ -19,7 +20,10 @@
using ::blink_testing::RecordedOpsAre;
using ::cc::ConcatOp;
using ::cc::DrawColorOp;
+using ::cc::DrawRectOp;
using ::cc::PaintOpEq;
+using ::cc::RestoreOp;
+using ::cc::SaveOp;
using ::cc::ScaleOp;
using ::cc::SetMatrixOp;
@@ -152,5 +156,73 @@
0, 0, 0, 1))));
}
+TEST(PaintRenderingContext2DTest, overdrawOptimizationNotApplied) {
+ PaintRenderingContext2DSettings* context_settings =
+ PaintRenderingContext2DSettings::Create();
+ PaintRenderingContext2D* ctx = MakeGarbageCollected<PaintRenderingContext2D>(
+ gfx::Size(kWidth, kHeight), context_settings, /*zoom=*/1,
+ scheduler::GetSingleThreadTaskRunnerForTesting());
+ NonThrowableExceptionState exception_state;
+ ctx->fillRect(1, 1, 1, 1);
+ ctx->save();
+ ctx->fillRect(2, 2, 2, 2);
+ ctx->clearRect(3, 3, 3, 3);
+ ctx->fillRect(4, 4, 4, 4);
+ ctx->restore(exception_state);
+
+ cc::PaintFlags clear_flags;
+ clear_flags.setBlendMode(SkBlendMode::kClear);
+
+ cc::PaintFlags rect_flags;
+ rect_flags.setAntiAlias(true);
+ rect_flags.setFilterQuality(cc::PaintFlags::FilterQuality::kLow);
+
+ EXPECT_THAT(
+ ctx->GetRecord(),
+ RecordedOpsAre(
+ PaintOpEq<DrawColorOp>(SkColors::kTransparent, SkBlendMode::kSrc),
+ PaintOpEq<DrawRectOp>(SkRect::MakeXYWH(1, 1, 1, 1), rect_flags),
+ PaintOpEq<SaveOp>(),
+ PaintOpEq<DrawRectOp>(SkRect::MakeXYWH(2, 2, 2, 2), rect_flags),
+ PaintOpEq<DrawRectOp>(SkRect::MakeXYWH(3, 3, 3, 3), clear_flags),
+ PaintOpEq<DrawRectOp>(SkRect::MakeXYWH(4, 4, 4, 4), rect_flags),
+ PaintOpEq<RestoreOp>()));
+}
+
+TEST(PaintRenderingContext2DTest, overdrawOptimizationApplied) {
+ PaintRenderingContext2DSettings* context_settings =
+ PaintRenderingContext2DSettings::Create();
+ PaintRenderingContext2D* ctx = MakeGarbageCollected<PaintRenderingContext2D>(
+ gfx::Size(kWidth, kHeight), context_settings, /*zoom=*/1,
+ scheduler::GetSingleThreadTaskRunnerForTesting());
+ NonThrowableExceptionState exception_state;
+ ctx->fillRect(1, 1, 1, 1);
+ ctx->save();
+ ctx->fillRect(2, 2, 2, 2);
+ // Clear the whole canvas, triggering overdraw optimization and discarding all
+ // previous draw commands.
+ ctx->clearRect(0, 0, kWidth, kHeight);
+ ctx->fillRect(3, 3, 3, 3);
+ ctx->restore(exception_state);
+
+ cc::PaintFlags clear_flags;
+ clear_flags.setBlendMode(SkBlendMode::kClear);
+
+ cc::PaintFlags rect_flags;
+ rect_flags.setAntiAlias(true);
+ rect_flags.setFilterQuality(cc::PaintFlags::FilterQuality::kLow);
+
+ // Draw calls done before the `clearRect` are discarded, but the matrix clip
+ // stack remains untouched.
+ EXPECT_THAT(
+ ctx->GetRecord(),
+ RecordedOpsAre(
+ PaintOpEq<SaveOp>(),
+ PaintOpEq<DrawRectOp>(SkRect::MakeXYWH(0, 0, kWidth, kHeight),
+ clear_flags),
+ PaintOpEq<DrawRectOp>(SkRect::MakeXYWH(3, 3, 3, 3), rect_flags),
+ PaintOpEq<RestoreOp>()));
+}
+
} // namespace
} // namespace blink