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