1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkBBHFactory.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkClipOp.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkFont.h"
15 #include "include/core/SkFontStyle.h"
16 #include "include/core/SkImage.h" // IWYU pragma: keep
17 #include "include/core/SkImageInfo.h"
18 #include "include/core/SkMatrix.h"
19 #include "include/core/SkPaint.h"
20 #include "include/core/SkPath.h"
21 #include "include/core/SkPathTypes.h"
22 #include "include/core/SkPicture.h"
23 #include "include/core/SkPictureRecorder.h"
24 #include "include/core/SkPixelRef.h"
25 #include "include/core/SkRect.h"
26 #include "include/core/SkRefCnt.h"
27 #include "include/core/SkSamplingOptions.h"
28 #include "include/core/SkScalar.h"
29 #include "include/core/SkStream.h"
30 #include "include/core/SkTypeface.h"
31 #include "include/core/SkTypes.h"
32 #include "src/base/SkRandom.h"
33 #include "src/core/SkBigPicture.h"
34 #include "src/core/SkPicturePriv.h"
35 #include "src/core/SkRectPriv.h"
36 #include "tests/Test.h"
37 
38 #include <cstddef>
39 #include <memory>
40 #include <vector>
41 
42 class SkRRect;
43 class SkRegion;
44 
make_bm(SkBitmap * bm,int w,int h,SkColor color,bool immutable)45 static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
46     bm->allocN32Pixels(w, h);
47     bm->eraseColor(color);
48     if (immutable) {
49         bm->setImmutable();
50     }
51 }
52 
53 #ifdef SK_DEBUG
54 // Ensure that deleting an empty SkPicture does not assert. Asserts only fire
55 // in debug mode, so only run in debug mode.
test_deleting_empty_picture()56 static void test_deleting_empty_picture() {
57     SkPictureRecorder recorder;
58     // Creates an SkPictureRecord
59     recorder.beginRecording(0, 0);
60     // Turns that into an SkPicture
61     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
62     // Ceates a new SkPictureRecord
63     recorder.beginRecording(0, 0);
64 }
65 
66 // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
test_serializing_empty_picture()67 static void test_serializing_empty_picture() {
68     SkPictureRecorder recorder;
69     recorder.beginRecording(0, 0);
70     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
71     SkDynamicMemoryWStream stream;
72     picture->serialize(&stream);
73 }
74 #endif
75 
rand_op(SkCanvas * canvas,SkRandom & rand)76 static void rand_op(SkCanvas* canvas, SkRandom& rand) {
77     SkPaint paint;
78     SkRect rect = SkRect::MakeWH(50, 50);
79 
80     SkScalar unit = rand.nextUScalar1();
81     if (unit <= 0.3) {
82 //        SkDebugf("save\n");
83         canvas->save();
84     } else if (unit <= 0.6) {
85 //        SkDebugf("restore\n");
86         canvas->restore();
87     } else if (unit <= 0.9) {
88 //        SkDebugf("clip\n");
89         canvas->clipRect(rect);
90     } else {
91 //        SkDebugf("draw\n");
92         canvas->drawPaint(paint);
93     }
94 }
95 
set_canvas_to_save_count_4(SkCanvas * canvas)96 static void set_canvas_to_save_count_4(SkCanvas* canvas) {
97     canvas->restoreToCount(1);
98     canvas->save();
99     canvas->save();
100     canvas->save();
101 }
102 
103 /**
104  * A canvas that records the number of saves, saveLayers and restores.
105  */
106 class SaveCountingCanvas : public SkCanvas {
107 public:
SaveCountingCanvas(int width,int height)108     SaveCountingCanvas(int width, int height)
109         : INHERITED(width, height)
110         , fSaveCount(0)
111         , fSaveLayerCount(0)
112         , fSaveBehindCount(0)
113         , fRestoreCount(0){
114     }
115 
getSaveLayerStrategy(const SaveLayerRec & rec)116     SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
117         ++fSaveLayerCount;
118         return this->INHERITED::getSaveLayerStrategy(rec);
119     }
120 
onDoSaveBehind(const SkRect * subset)121     bool onDoSaveBehind(const SkRect* subset) override {
122         ++fSaveBehindCount;
123         return this->INHERITED::onDoSaveBehind(subset);
124     }
125 
willSave()126     void willSave() override {
127         ++fSaveCount;
128         this->INHERITED::willSave();
129     }
130 
willRestore()131     void willRestore() override {
132         ++fRestoreCount;
133         this->INHERITED::willRestore();
134     }
135 
getSaveCount() const136     unsigned int getSaveCount() const { return fSaveCount; }
getSaveLayerCount() const137     unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
getSaveBehindCount() const138     unsigned int getSaveBehindCount() const { return fSaveBehindCount; }
getRestoreCount() const139     unsigned int getRestoreCount() const { return fRestoreCount; }
140 
141 private:
142     unsigned int fSaveCount;
143     unsigned int fSaveLayerCount;
144     unsigned int fSaveBehindCount;
145     unsigned int fRestoreCount;
146 
147     using INHERITED = SkCanvas;
148 };
149 
check_save_state(skiatest::Reporter * reporter,SkPicture * picture,unsigned int numSaves,unsigned int numSaveLayers,unsigned int numRestores)150 void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
151                       unsigned int numSaves, unsigned int numSaveLayers,
152                       unsigned int numRestores) {
153     SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
154                               SkScalarCeilToInt(picture->cullRect().height()));
155 
156     picture->playback(&canvas);
157 
158     // Optimizations may have removed these,
159     // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
160     REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
161     REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
162     REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
163 }
164 
165 // This class exists so SkPicture can friend it and give it access to
166 // the 'partialReplay' method.
167 class SkPictureRecorderReplayTester {
168 public:
Copy(SkPictureRecorder * recorder)169     static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) {
170         SkPictureRecorder recorder2;
171 
172         SkCanvas* canvas = recorder2.beginRecording(10, 10);
173 
174         recorder->partialReplay(canvas);
175 
176         return recorder2.finishRecordingAsPicture();
177     }
178 };
179 
create_imbalance(SkCanvas * canvas)180 static void create_imbalance(SkCanvas* canvas) {
181     SkRect clipRect = SkRect::MakeWH(2, 2);
182     SkRect drawRect = SkRect::MakeWH(10, 10);
183     canvas->save();
184         canvas->clipRect(clipRect, SkClipOp::kIntersect);
185         canvas->translate(1.0f, 1.0f);
186         SkPaint p;
187         p.setColor(SK_ColorGREEN);
188         canvas->drawRect(drawRect, p);
189     // no restore
190 }
191 
192 // This tests that replaying a potentially unbalanced picture into a canvas
193 // doesn't affect the canvas' save count or matrix/clip state.
check_balance(skiatest::Reporter * reporter,SkPicture * picture)194 static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
195     SkBitmap bm;
196     bm.allocN32Pixels(4, 3);
197     SkCanvas canvas(bm);
198 
199     int beforeSaveCount = canvas.getSaveCount();
200 
201     SkMatrix beforeMatrix = canvas.getTotalMatrix();
202 
203     SkRect beforeClip = canvas.getLocalClipBounds();
204 
205     canvas.drawPicture(picture);
206 
207     REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
208     REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
209 
210     SkRect afterClip = canvas.getLocalClipBounds();
211 
212     REPORTER_ASSERT(reporter, afterClip == beforeClip);
213 }
214 
215 // Test out SkPictureRecorder::partialReplay
DEF_TEST(PictureRecorder_replay,reporter)216 DEF_TEST(PictureRecorder_replay, reporter) {
217     // check save/saveLayer state
218     {
219         SkPictureRecorder recorder;
220 
221         SkCanvas* canvas = recorder.beginRecording(10, 10);
222 
223         canvas->saveLayer(nullptr, nullptr);
224 
225         sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
226 
227         // The extra save and restore comes from the Copy process.
228         check_save_state(reporter, copy.get(), 2, 1, 3);
229 
230         canvas->saveLayer(nullptr, nullptr);
231 
232         sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
233 
234         check_save_state(reporter, final.get(), 1, 2, 3);
235 
236         // The copy shouldn't pick up any operations added after it was made
237         check_save_state(reporter, copy.get(), 2, 1, 3);
238     }
239 
240     // Recreate the Android partialReplay test case
241     {
242         SkPictureRecorder recorder;
243 
244         SkCanvas* canvas = recorder.beginRecording(4, 3);
245         create_imbalance(canvas);
246 
247         int expectedSaveCount = canvas->getSaveCount();
248 
249         sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
250         check_balance(reporter, copy.get());
251 
252         REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
253 
254         // End the recording of source to test the picture finalization
255         // process isn't complicated by the partialReplay step
256         sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
257     }
258 }
259 
test_unbalanced_save_restores(skiatest::Reporter * reporter)260 static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
261     SkCanvas testCanvas(100, 100);
262     set_canvas_to_save_count_4(&testCanvas);
263 
264     REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
265 
266     SkPaint paint;
267     SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
268 
269     SkPictureRecorder recorder;
270 
271     {
272         // Create picture with 2 unbalanced saves
273         SkCanvas* canvas = recorder.beginRecording(100, 100);
274         canvas->save();
275         canvas->translate(10, 10);
276         canvas->drawRect(rect, paint);
277         canvas->save();
278         canvas->translate(10, 10);
279         canvas->drawRect(rect, paint);
280         sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture());
281 
282         testCanvas.drawPicture(extraSavePicture);
283         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
284     }
285 
286     set_canvas_to_save_count_4(&testCanvas);
287 
288     {
289         // Create picture with 2 unbalanced restores
290         SkCanvas* canvas = recorder.beginRecording(100, 100);
291         canvas->save();
292         canvas->translate(10, 10);
293         canvas->drawRect(rect, paint);
294         canvas->save();
295         canvas->translate(10, 10);
296         canvas->drawRect(rect, paint);
297         canvas->restore();
298         canvas->restore();
299         canvas->restore();
300         canvas->restore();
301         sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture());
302 
303         testCanvas.drawPicture(extraRestorePicture);
304         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
305     }
306 
307     set_canvas_to_save_count_4(&testCanvas);
308 
309     {
310         SkCanvas* canvas = recorder.beginRecording(100, 100);
311         canvas->translate(10, 10);
312         canvas->drawRect(rect, paint);
313         sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture());
314 
315         testCanvas.drawPicture(noSavePicture);
316         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
317         REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
318     }
319 }
320 
test_peephole()321 static void test_peephole() {
322     SkRandom rand;
323 
324     SkPictureRecorder recorder;
325 
326     for (int j = 0; j < 100; j++) {
327         SkRandom rand2(rand); // remember the seed
328 
329         SkCanvas* canvas = recorder.beginRecording(100, 100);
330 
331         for (int i = 0; i < 1000; ++i) {
332             rand_op(canvas, rand);
333         }
334         sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
335 
336         rand = rand2;
337     }
338 
339     {
340         SkCanvas* canvas = recorder.beginRecording(100, 100);
341         SkRect rect = SkRect::MakeWH(50, 50);
342 
343         for (int i = 0; i < 100; ++i) {
344             canvas->save();
345         }
346         while (canvas->getSaveCount() > 1) {
347             canvas->clipRect(rect);
348             canvas->restore();
349         }
350         sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
351     }
352 }
353 
test_bad_bitmap(skiatest::Reporter * reporter)354 static void test_bad_bitmap(skiatest::Reporter* reporter) {
355     // missing pixels should return null for image
356     SkBitmap bm;
357     bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
358     auto img = bm.asImage();
359     REPORTER_ASSERT(reporter, !img);
360 
361     // make sure we don't crash on a null image
362     SkPictureRecorder recorder;
363     SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
364     recordingCanvas->drawImage(nullptr, 0, 0);
365     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
366 
367     SkCanvas canvas;
368     canvas.drawPicture(picture);
369 }
370 
test_clip_bound_opt(skiatest::Reporter * reporter)371 static void test_clip_bound_opt(skiatest::Reporter* reporter) {
372     // Test for crbug.com/229011
373     SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
374                                     SkIntToScalar(2), SkIntToScalar(2));
375     SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
376                                     SkIntToScalar(1), SkIntToScalar(1));
377     SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
378                                     SkIntToScalar(1), SkIntToScalar(1));
379 
380     SkPath invPath;
381     invPath.addOval(rect1);
382     invPath.setFillType(SkPathFillType::kInverseEvenOdd);
383     SkPath path;
384     path.addOval(rect2);
385     SkPath path2;
386     path2.addOval(rect3);
387     SkIRect clipBounds;
388     SkPictureRecorder recorder;
389 
390     // Testing conservative-raster-clip that is enabled by PictureRecord
391     {
392         SkCanvas* canvas = recorder.beginRecording(10, 10);
393         canvas->clipPath(invPath);
394         clipBounds = canvas->getDeviceClipBounds();
395         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
396         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
397         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
398         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
399     }
400     {
401         SkCanvas* canvas = recorder.beginRecording(10, 10);
402         canvas->clipPath(path);
403         canvas->clipPath(invPath);
404         clipBounds = canvas->getDeviceClipBounds();
405         REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
406         REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
407         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
408         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
409     }
410     {
411         SkCanvas* canvas = recorder.beginRecording(10, 10);
412         canvas->clipPath(path, SkClipOp::kDifference);
413         clipBounds = canvas->getDeviceClipBounds();
414         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
415         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
416         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
417         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
418     }
419     {
420         SkCanvas* canvas = recorder.beginRecording(10, 10);
421         canvas->clipPath(path, SkClipOp::kIntersect);
422         canvas->clipPath(path2, SkClipOp::kDifference);
423         clipBounds = canvas->getDeviceClipBounds();
424         REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
425         REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
426         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
427         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
428     }
429 }
430 
test_cull_rect_reset(skiatest::Reporter * reporter)431 static void test_cull_rect_reset(skiatest::Reporter* reporter) {
432     SkPictureRecorder recorder;
433     SkRect bounds = SkRect::MakeWH(10, 10);
434     SkRTreeFactory factory;
435     SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
436     bounds = SkRect::MakeWH(100, 100);
437     SkPaint paint;
438     canvas->drawRect(bounds, paint);
439     canvas->drawRect(bounds, paint);
440     sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds));
441     const SkBigPicture* picture = SkPicturePriv::AsSkBigPicture(p);
442     REPORTER_ASSERT(reporter, picture);
443 
444     SkRect finalCullRect = picture->cullRect();
445     REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
446     REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
447     REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
448     REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
449 }
450 
451 
452 /**
453  * A canvas that records the number of clip commands.
454  */
455 class ClipCountingCanvas : public SkCanvas {
456 public:
ClipCountingCanvas(int width,int height)457     ClipCountingCanvas(int width, int height)
458         : INHERITED(width, height)
459         , fClipCount(0){
460     }
461 
onClipRect(const SkRect & r,SkClipOp op,ClipEdgeStyle edgeStyle)462     void onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) override {
463         fClipCount += 1;
464         this->INHERITED::onClipRect(r, op, edgeStyle);
465     }
466 
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)467     void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle)override {
468         fClipCount += 1;
469         this->INHERITED::onClipRRect(rrect, op, edgeStyle);
470     }
471 
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)472     void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) override {
473         fClipCount += 1;
474         this->INHERITED::onClipPath(path, op, edgeStyle);
475     }
476 
onClipRegion(const SkRegion & deviceRgn,SkClipOp op)477     void onClipRegion(const SkRegion& deviceRgn, SkClipOp op) override {
478         fClipCount += 1;
479         this->INHERITED::onClipRegion(deviceRgn, op);
480     }
481 
getClipCount() const482     unsigned getClipCount() const { return fClipCount; }
483 
484 private:
485     unsigned fClipCount;
486 
487     using INHERITED = SkCanvas;
488 };
489 
test_gen_id(skiatest::Reporter * reporter)490 static void test_gen_id(skiatest::Reporter* reporter) {
491 
492     SkPictureRecorder recorder;
493     recorder.beginRecording(0, 0);
494     sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture());
495 
496     // Empty pictures should still have a valid ID
497     REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
498 
499     SkCanvas* canvas = recorder.beginRecording(1, 1);
500     canvas->drawColor(SK_ColorWHITE);
501     sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture());
502     // picture should have a non-zero id after recording
503     REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
504 
505     // both pictures should have different ids
506     REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
507 }
508 
test_typeface(skiatest::Reporter * reporter)509 static void test_typeface(skiatest::Reporter* reporter) {
510     SkPictureRecorder recorder;
511     SkCanvas* canvas = recorder.beginRecording(10, 10);
512     SkFont font(SkTypeface::MakeFromName("Arial", SkFontStyle::Italic()));
513     canvas->drawString("Q", 0, 10, font, SkPaint());
514     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
515     SkDynamicMemoryWStream stream;
516     picture->serialize(&stream);
517 }
518 
DEF_TEST(Picture,reporter)519 DEF_TEST(Picture, reporter) {
520     test_typeface(reporter);
521 #ifdef SK_DEBUG
522     test_deleting_empty_picture();
523     test_serializing_empty_picture();
524 #endif
525     test_bad_bitmap(reporter);
526     test_unbalanced_save_restores(reporter);
527     test_peephole();
528     test_clip_bound_opt(reporter);
529     test_gen_id(reporter);
530     test_cull_rect_reset(reporter);
531 }
532 
draw_bitmaps(const SkBitmap bitmap,SkCanvas * canvas)533 static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
534     const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
535     auto img = bitmap.asImage();
536 
537     // Don't care what these record, as long as they're legal.
538     canvas->drawImage(img, 0.0f, 0.0f);
539     canvas->drawImageRect(img, rect, rect, SkSamplingOptions(), nullptr,
540                           SkCanvas::kStrict_SrcRectConstraint);
541     canvas->drawImage(img, 1, 1);   // drawSprite
542 }
543 
test_draw_bitmaps(SkCanvas * canvas)544 static void test_draw_bitmaps(SkCanvas* canvas) {
545     SkBitmap empty;
546     draw_bitmaps(empty, canvas);
547     empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
548     draw_bitmaps(empty, canvas);
549 }
550 
DEF_TEST(Picture_EmptyBitmap,r)551 DEF_TEST(Picture_EmptyBitmap, r) {
552     SkPictureRecorder recorder;
553     test_draw_bitmaps(recorder.beginRecording(10, 10));
554     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
555 }
556 
DEF_TEST(Canvas_EmptyBitmap,r)557 DEF_TEST(Canvas_EmptyBitmap, r) {
558     SkBitmap dst;
559     dst.allocN32Pixels(10, 10);
560     SkCanvas canvas(dst);
561 
562     test_draw_bitmaps(&canvas);
563 }
564 
DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore,reporter)565 DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
566     // This test is from crbug.com/344987.
567     // The commands are:
568     //   saveLayer with paint that modifies alpha
569     //     drawBitmapRect
570     //     drawBitmapRect
571     //   restore
572     // The bug was that this structure was modified so that:
573     //  - The saveLayer and restore were eliminated
574     //  - The alpha was only applied to the first drawBitmapRectToRect
575 
576     // This test draws blue and red squares inside a 50% transparent
577     // layer.  Both colours should show up muted.
578     // When the bug is present, the red square (the second bitmap)
579     // shows upwith full opacity.
580 
581     SkBitmap blueBM;
582     make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
583     SkBitmap redBM;
584     make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
585     SkPaint semiTransparent;
586     semiTransparent.setAlpha(0x80);
587 
588     SkPictureRecorder recorder;
589     SkCanvas* canvas = recorder.beginRecording(100, 100);
590     canvas->drawColor(0);
591 
592     canvas->saveLayer(nullptr, &semiTransparent);
593     canvas->drawImage(blueBM.asImage(), 25, 25);
594     canvas->drawImage(redBM.asImage(), 50, 50);
595     canvas->restore();
596 
597     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
598 
599     // Now replay the picture back on another canvas
600     // and check a couple of its pixels.
601     SkBitmap replayBM;
602     make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
603     SkCanvas replayCanvas(replayBM);
604     picture->playback(&replayCanvas);
605 
606     // With the bug present, at (55, 55) we would get a fully opaque red
607     // intead of a dark red.
608     REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
609     REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
610 }
611 
612 struct CountingBBH : public SkBBoxHierarchy {
613     mutable int searchCalls;
614 
CountingBBHCountingBBH615     CountingBBH() : searchCalls(0) {}
616 
searchCountingBBH617     void search(const SkRect& query, std::vector<int>* results) const override {
618         this->searchCalls++;
619     }
620 
insertCountingBBH621     void insert(const SkRect[], int) override {}
bytesUsedCountingBBH622     size_t bytesUsed() const override { return 0; }
623 };
624 
625 class SpoonFedBBHFactory : public SkBBHFactory {
626 public:
SpoonFedBBHFactory(sk_sp<SkBBoxHierarchy> bbh)627     explicit SpoonFedBBHFactory(sk_sp<SkBBoxHierarchy> bbh) : fBBH(bbh) {}
operator ()() const628     sk_sp<SkBBoxHierarchy> operator()() const override {
629         return fBBH;
630     }
631 private:
632     sk_sp<SkBBoxHierarchy> fBBH;
633 };
634 
635 // When the canvas clip covers the full picture, we don't need to call the BBH.
DEF_TEST(Picture_SkipBBH,r)636 DEF_TEST(Picture_SkipBBH, r) {
637     SkRect bound = SkRect::MakeWH(320, 240);
638 
639     auto bbh = sk_make_sp<CountingBBH>();
640     SpoonFedBBHFactory factory(bbh);
641 
642     SkPictureRecorder recorder;
643     SkCanvas* c = recorder.beginRecording(bound, &factory);
644     // Record a few ops so we don't hit a small- or empty- picture optimization.
645         c->drawRect(bound, SkPaint());
646         c->drawRect(bound, SkPaint());
647     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
648 
649     SkCanvas big(640, 480), small(300, 200);
650 
651     picture->playback(&big);
652     REPORTER_ASSERT(r, bbh->searchCalls == 0);
653 
654     picture->playback(&small);
655     REPORTER_ASSERT(r, bbh->searchCalls == 1);
656 }
657 
DEF_TEST(Picture_BitmapLeak,r)658 DEF_TEST(Picture_BitmapLeak, r) {
659     SkBitmap mut, immut;
660     mut.allocN32Pixels(300, 200);
661     immut.allocN32Pixels(300, 200);
662     immut.setImmutable();
663     SkASSERT(!mut.isImmutable());
664     SkASSERT(immut.isImmutable());
665 
666     // No one can hold a ref on our pixels yet.
667     REPORTER_ASSERT(r, mut.pixelRef()->unique());
668     REPORTER_ASSERT(r, immut.pixelRef()->unique());
669 
670     sk_sp<SkPicture> pic;
671     {
672         // we want the recorder to go out of scope before our subsequent checks, so we
673         // place it inside local braces.
674         SkPictureRecorder rec;
675         SkCanvas* canvas = rec.beginRecording(1920, 1200);
676             canvas->drawImage(mut.asImage(), 0, 0);
677             canvas->drawImage(immut.asImage(), 800, 600);
678         pic = rec.finishRecordingAsPicture();
679     }
680 
681     // The picture shares the immutable pixels but copies the mutable ones.
682     REPORTER_ASSERT(r, mut.pixelRef()->unique());
683     REPORTER_ASSERT(r, !immut.pixelRef()->unique());
684 
685     // When the picture goes away, it's just our bitmaps holding the refs.
686     pic = nullptr;
687     REPORTER_ASSERT(r, mut.pixelRef()->unique());
688     REPORTER_ASSERT(r, immut.pixelRef()->unique());
689 }
690 
691 // getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
DEF_TEST(Picture_getRecordingCanvas,r)692 DEF_TEST(Picture_getRecordingCanvas, r) {
693     SkPictureRecorder rec;
694     REPORTER_ASSERT(r, !rec.getRecordingCanvas());
695     for (int i = 0; i < 3; i++) {
696         rec.beginRecording(100, 100);
697         REPORTER_ASSERT(r, rec.getRecordingCanvas());
698         rec.finishRecordingAsPicture();
699         REPORTER_ASSERT(r, !rec.getRecordingCanvas());
700     }
701 }
702 
DEF_TEST(Picture_preserveCullRect,r)703 DEF_TEST(Picture_preserveCullRect, r) {
704     SkPictureRecorder recorder;
705 
706     SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
707     c->clear(SK_ColorCYAN);
708 
709     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
710     SkDynamicMemoryWStream wstream;
711     picture->serialize(&wstream);
712 
713     std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
714     sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream.get()));
715 
716     REPORTER_ASSERT(r, deserializedPicture != nullptr);
717     REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
718     REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
719     REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
720     REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
721 }
722 
723 
724 // If we record bounded ops into a picture with a big cull and calculate the
725 // bounds of those ops, we should trim down the picture cull to the ops' bounds.
726 // If we're not using an SkBBH, we shouldn't change it.
DEF_TEST(Picture_UpdatedCull_1,r)727 DEF_TEST(Picture_UpdatedCull_1, r) {
728     SkRTreeFactory factory;
729     SkPictureRecorder recorder;
730 
731     auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory);
732     canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
733     auto pic = recorder.finishRecordingAsPicture();
734     REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,20));
735 
736     canvas = recorder.beginRecording(SkRectPriv::MakeLargest());
737     canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
738     pic = recorder.finishRecordingAsPicture();
739     REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest());
740 }
DEF_TEST(Picture_UpdatedCull_2,r)741 DEF_TEST(Picture_UpdatedCull_2, r) {
742     SkRTreeFactory factory;
743     SkPictureRecorder recorder;
744 
745     auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory);
746     canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
747     canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
748     auto pic = recorder.finishRecordingAsPicture();
749     REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,40));
750 
751     canvas = recorder.beginRecording(SkRectPriv::MakeLargest());
752     canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
753     canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
754     pic = recorder.finishRecordingAsPicture();
755     REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest());
756 }
757 
DEF_TEST(Picture_RecordsFlush,r)758 DEF_TEST(Picture_RecordsFlush, r) {
759     SkPictureRecorder recorder;
760 
761     auto canvas = recorder.beginRecording(SkRect::MakeWH(100,100));
762     for (int i = 0; i < 10; i++) {
763         canvas->clear(0);
764         for (int j = 0; j < 10; j++) {
765             canvas->drawRect(SkRect::MakeXYWH(i*10,j*10,10,10), SkPaint());
766         }
767         canvas->flush();
768     }
769 
770     // Did we record the flushes?
771     auto pic = recorder.finishRecordingAsPicture();
772     REPORTER_ASSERT(r, pic->approximateOpCount() == 120);  // 10 clears, 100 draws, 10 flushes
773 
774     // Do we serialize and deserialize flushes?
775     auto skp = pic->serialize();
776     auto back = SkPicture::MakeFromData(skp->data(), skp->size());
777     REPORTER_ASSERT(r, back->approximateOpCount() == pic->approximateOpCount());
778 }
779 
DEF_TEST(Placeholder,r)780 DEF_TEST(Placeholder, r) {
781     SkRect cull = { 0,0, 10,20 };
782 
783     // Each placeholder is unique.
784     sk_sp<SkPicture> p1 = SkPicture::MakePlaceholder(cull),
785                      p2 = SkPicture::MakePlaceholder(cull);
786     REPORTER_ASSERT(r, p1->cullRect() == p2->cullRect());
787     REPORTER_ASSERT(r, p1->cullRect() == cull);
788     REPORTER_ASSERT(r, p1->uniqueID() != p2->uniqueID());
789 
790     // Placeholders are never unrolled by SkCanvas (while other small pictures may be).
791     SkPictureRecorder recorder;
792     SkCanvas* canvas = recorder.beginRecording(cull);
793         canvas->drawPicture(p1);
794         canvas->drawPicture(p2);
795     sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
796     REPORTER_ASSERT(r, pic->approximateOpCount() == 2);
797 
798     // Any upper limit when recursing into nested placeholders is fine as long
799     // as it doesn't overflow an int.
800     REPORTER_ASSERT(r, pic->approximateOpCount(/*nested?*/true) >=  2);
801     REPORTER_ASSERT(r, pic->approximateOpCount(/*nested?*/true) <= 10);
802 }
803 
DEF_TEST(Picture_empty_serial,reporter)804 DEF_TEST(Picture_empty_serial, reporter) {
805     SkPictureRecorder rec;
806     (void)rec.beginRecording(10, 10);
807     auto pic = rec.finishRecordingAsPicture();
808     REPORTER_ASSERT(reporter, pic);
809 
810     auto data = pic->serialize();
811     REPORTER_ASSERT(reporter, data);
812 
813     auto pic2 = SkPicture::MakeFromData(data->data(), data->size());
814     REPORTER_ASSERT(reporter, pic2);
815 }
816 
817 
DEF_TEST(Picture_drawsNothing,r)818 DEF_TEST(Picture_drawsNothing, r) {
819     // Tests that pic->cullRect().isEmpty() is a good way to test a picture
820     // recorded with an R-tree draws nothing.
821     struct {
822         bool draws_nothing;
823         void (*fn)(SkCanvas*);
824     } cases[] = {
825         {  true, [](SkCanvas* c) {                                                             } },
826         {  true, [](SkCanvas* c) { c->save();                                    c->restore(); } },
827         {  true, [](SkCanvas* c) { c->save(); c->clipRect({0,0,5,5});            c->restore(); } },
828         {  true, [](SkCanvas* c) {            c->clipRect({0,0,5,5});                          } },
829 
830         { false, [](SkCanvas* c) {            c->drawRect({0,0,5,5}, SkPaint{});               } },
831         { false, [](SkCanvas* c) { c->save(); c->drawRect({0,0,5,5}, SkPaint{}); c->restore(); } },
832         { false, [](SkCanvas* c) {
833             c->drawRect({0,0, 5, 5}, SkPaint{});
834             c->drawRect({5,5,10,10}, SkPaint{});
835         }},
836     };
837 
838     for (const auto& c : cases) {
839         SkPictureRecorder rec;
840         SkRTreeFactory factory;
841         c.fn(rec.beginRecording(10,10, &factory));
842         sk_sp<SkPicture> pic = rec.finishRecordingAsPicture();
843 
844         REPORTER_ASSERT(r, pic->cullRect().isEmpty() == c.draws_nothing);
845     }
846 }
847 
DEF_TEST(Picture_emptyNestedPictureBug,r)848 DEF_TEST(Picture_emptyNestedPictureBug, r) {
849     const SkRect bounds = {-5000, -5000, 5000, 5000};
850 
851     SkPictureRecorder recorder;
852     SkRTreeFactory factory;
853 
854     // These three pictures should all draw the same but due to bugs they don't:
855     //
856     //   1) inner has enough content that it is recoreded as an SkBigPicture,
857     //      and all its content falls outside the positive/positive quadrant,
858     //      and it is recorded with an R-tree so we contract the cullRect to those bounds;
859     //
860     //   2) middle wraps inner,
861     //      and it its recorded with an R-tree so we update middle's cullRect to inner's;
862     //
863     //   3) outer wraps inner,
864     //      and notices that middle contains only one op, drawPicture(inner),
865     //      so it plays middle back during recording rather than ref'ing middle,
866     //      querying middle's R-tree with its SkCanvas' bounds* {0,0, 5000,5000},
867     //      finding nothing to draw.
868     //
869     //  * The bug was that these bounds were not tracked as {-5000,-5000, 5000,5000}.
870     {
871         SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
872         canvas->translate(-100,-100);
873         canvas->drawRect({0,0,50,50}, SkPaint{});
874     }
875     sk_sp<SkPicture> inner = recorder.finishRecordingAsPicture();
876 
877     recorder.beginRecording(bounds, &factory)->drawPicture(inner);
878     sk_sp<SkPicture> middle = recorder.finishRecordingAsPicture();
879 
880     // This doesn't need &factory to reproduce the bug,
881     // but it's nice to see we come up with the same {-100,-100, -50,-50} bounds.
882     recorder.beginRecording(bounds, &factory)->drawPicture(middle);
883     sk_sp<SkPicture> outer = recorder.finishRecordingAsPicture();
884 
885     REPORTER_ASSERT(r, (inner ->cullRect() == SkRect{-100,-100, -50,-50}));
886     REPORTER_ASSERT(r, (middle->cullRect() == SkRect{-100,-100, -50,-50}));
887     REPORTER_ASSERT(r, (outer ->cullRect() == SkRect{-100,-100, -50,-50}));   // Used to fail.
888 }
889 
DEF_TEST(Picture_fillsBBH,r)890 DEF_TEST(Picture_fillsBBH, r) {
891     // Test empty (0 draws), mini (1 draw), and big (2+) pictures, making sure they fill the BBH.
892     const SkRect rects[] = {
893         { 0, 0, 20,20},
894         {20,20, 40,40},
895     };
896 
897     for (int n = 0; n <= 2; n++) {
898         SkRTreeFactory factory;
899         SkPictureRecorder rec;
900 
901         sk_sp<SkBBoxHierarchy> bbh = factory();
902 
903         SkCanvas* c = rec.beginRecording({0,0, 100,100}, bbh);
904         for (int i = 0; i < n; i++) {
905             c->drawRect(rects[i], SkPaint{});
906         }
907         sk_sp<SkPicture> pic = rec.finishRecordingAsPicture();
908 
909         std::vector<int> results;
910         bbh->search({0,0, 100,100}, &results);
911         REPORTER_ASSERT(r, (int)results.size() == n,
912                         "results.size() == %d, want %d\n", (int)results.size(), n);
913     }
914 }
915 
DEF_TEST(Picture_nested_op_count,r)916 DEF_TEST(Picture_nested_op_count, r) {
917     auto make_pic = [](int n, sk_sp<SkPicture> pic) {
918         SkPictureRecorder rec;
919         SkCanvas* c = rec.beginRecording({0,0, 100,100});
920         for (int i = 0; i < n; i++) {
921             if (pic) {
922                 c->drawPicture(pic);
923             } else {
924                 c->drawRect({0,0, 100,100}, SkPaint{});
925             }
926         }
927         return rec.finishRecordingAsPicture();
928     };
929 
930     auto check = [r](sk_sp<SkPicture> pic, int shallow, int nested) {
931         int s = pic->approximateOpCount(false);
932         int n = pic->approximateOpCount(true);
933         REPORTER_ASSERT(r, s == shallow);
934         REPORTER_ASSERT(r, n == nested);
935     };
936 
937     sk_sp<SkPicture> leaf1 = make_pic(1, nullptr);
938     check(leaf1, 1, 1);
939 
940     sk_sp<SkPicture> leaf10 = make_pic(10, nullptr);
941     check(leaf10, 10, 10);
942 
943     check(make_pic( 1, leaf1),   1,   1);
944     check(make_pic( 1, leaf10),  1,  10);
945     check(make_pic(10, leaf1),  10,  10);
946     check(make_pic(10, leaf10), 10, 100);
947 }
948