Fix end-of-pattern matching for Skia recording optimization.
The recorder optimizer's pattern matcher was accepting command sequences
when it shouldn't have.
In the submitted case, and the pattern matcher was looking for:
saveLayer, drawBitmap, restore
and in the rendering for the submitted case, the sequence of commands
were:
saveLayer, drawBitmap, drawBitmap, restore
This sequence was improperly accepted by the matcher, and the optimizer
reduced the sequence to:
drawBitmap, drawBitmap
where the opacity from the saveLayer paint argument was applied
to the first drawBitmap only.
The user-visible effect in Chrome was a flashing effect on an image
caused by incorrect (too-high) opacity.
The patch adds a Skia test to check for pixel colour values in
a similarly structured recording. All other Skia tests pass.
Blink layout tests also pass with this change.
BUG=chromium:344987
R=robertphillips@google.com, reed@google.com, mtklein@google.com
Author: dneto@chromium.org
Review URL: https://codereview.chromium.org/430503004
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 566cb19..ab4c3fa 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -319,7 +319,6 @@
return false;
}
- curOffset += curSize;
if (curOffset < writer->bytesWritten()) {
// Something else between the last command and the end of the stream
return false;
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index 95ceb05..7abef0e 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -1610,3 +1610,51 @@
test_draw_bitmaps(&canvas);
}
+
+DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
+ // This test is from crbug.com/344987.
+ // The commands are:
+ // saveLayer with paint that modifies alpha
+ // drawBitmapRectToRect
+ // drawBitmapRectToRect
+ // restore
+ // The bug was that this structure was modified so that:
+ // - The saveLayer and restore were eliminated
+ // - The alpha was only applied to the first drawBitmapRectToRect
+
+ // This test draws blue and red squares inside a 50% transparent
+ // layer. Both colours should show up muted.
+ // When the bug is present, the red square (the second bitmap)
+ // shows upwith full opacity.
+
+ SkBitmap blueBM;
+ make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
+ SkBitmap redBM;
+ make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
+ SkPaint semiTransparent;
+ semiTransparent.setAlpha(0x80);
+
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(100, 100);
+ canvas->drawARGB(0, 0, 0, 0);
+
+ canvas->saveLayer(0, &semiTransparent);
+ canvas->drawBitmap(blueBM, 25, 25);
+ canvas->drawBitmap(redBM, 50, 50);
+ canvas->restore();
+
+ SkAutoTUnref<SkPicture> picture(recorder.endRecording());
+
+ // Now replay the picture back on another canvas
+ // and check a couple of its pixels.
+ SkBitmap replayBM;
+ make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
+ SkCanvas replayCanvas(replayBM);
+ picture->draw(&replayCanvas);
+ replayCanvas.flush();
+
+ // With the bug present, at (55, 55) we would get a fully opaque red
+ // intead of a dark red.
+ REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
+ REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
+}