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 "SkBBoxHierarchy.h"
9 #include "SkBlurImageFilter.h"
10 #include "SkCanvas.h"
11 #include "SkColorMatrixFilter.h"
12 #include "SkColorPriv.h"
13 #include "SkDashPathEffect.h"
14 #include "SkData.h"
15 #include "SkImageGenerator.h"
16 #include "SkError.h"
17 #include "SkImageEncoder.h"
18 #include "SkImageGenerator.h"
19 #include "SkLayerInfo.h"
20 #include "SkMD5.h"
21 #include "SkPaint.h"
22 #include "SkPicture.h"
23 #include "SkPictureRecorder.h"
24 #include "SkPictureUtils.h"
25 #include "SkPixelRef.h"
26 #include "SkPixelSerializer.h"
27 #include "SkMiniRecorder.h"
28 #include "SkRRect.h"
29 #include "SkRandom.h"
30 #include "SkRecord.h"
31 #include "SkShader.h"
32 #include "SkStream.h"
33 #include "sk_tool_utils.h"
34 
35 #include "Test.h"
36 
37 #include "SkLumaColorFilter.h"
38 #include "SkColorFilterImageFilter.h"
39 
make_bm(SkBitmap * bm,int w,int h,SkColor color,bool immutable)40 static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
41     bm->allocN32Pixels(w, h);
42     bm->eraseColor(color);
43     if (immutable) {
44         bm->setImmutable();
45     }
46 }
47 
48 // For a while willPlayBackBitmaps() ignored SkImages and just looked for SkBitmaps.
test_images_are_found_by_willPlayBackBitmaps(skiatest::Reporter * reporter)49 static void test_images_are_found_by_willPlayBackBitmaps(skiatest::Reporter* reporter) {
50     // We just need _some_ SkImage
51     const SkPMColor pixel = 0;
52     const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
53     SkAutoTUnref<SkImage> image(SkImage::NewRasterCopy(info, &pixel, sizeof(pixel)));
54 
55     SkPictureRecorder recorder;
56     recorder.beginRecording(100,100)->drawImage(image, 0,0);
57     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
58 
59     REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps());
60 }
61 
62 /* Hit a few SkPicture::Analysis cases not handled elsewhere. */
test_analysis(skiatest::Reporter * reporter)63 static void test_analysis(skiatest::Reporter* reporter) {
64     SkPictureRecorder recorder;
65 
66     SkCanvas* canvas = recorder.beginRecording(100, 100);
67     {
68         canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ());
69     }
70     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
71     REPORTER_ASSERT(reporter, !picture->willPlayBackBitmaps());
72 
73     canvas = recorder.beginRecording(100, 100);
74     {
75         SkPaint paint;
76         // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader
77         // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here.
78         SkBitmap bitmap;
79         bitmap.allocPixels(SkImageInfo::MakeN32Premul(2, 2));
80         bitmap.eraseColor(SK_ColorBLUE);
81         *(bitmap.getAddr32(0, 0)) = SK_ColorGREEN;
82         SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode,
83                                                         SkShader::kClamp_TileMode);
84         paint.setShader(shader)->unref();
85         REPORTER_ASSERT(reporter, shader->isABitmap());
86 
87         canvas->drawRect(SkRect::MakeWH(10, 10), paint);
88     }
89     picture.reset(recorder.endRecording());
90     REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps());
91 }
92 
93 
94 #ifdef SK_DEBUG
95 // Ensure that deleting an empty SkPicture does not assert. Asserts only fire
96 // in debug mode, so only run in debug mode.
test_deleting_empty_picture()97 static void test_deleting_empty_picture() {
98     SkPictureRecorder recorder;
99     // Creates an SkPictureRecord
100     recorder.beginRecording(0, 0);
101     // Turns that into an SkPicture
102     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
103     // Ceates a new SkPictureRecord
104     recorder.beginRecording(0, 0);
105 }
106 
107 // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
test_serializing_empty_picture()108 static void test_serializing_empty_picture() {
109     SkPictureRecorder recorder;
110     recorder.beginRecording(0, 0);
111     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
112     SkDynamicMemoryWStream stream;
113     picture->serialize(&stream);
114 }
115 #endif
116 
rand_op(SkCanvas * canvas,SkRandom & rand)117 static void rand_op(SkCanvas* canvas, SkRandom& rand) {
118     SkPaint paint;
119     SkRect rect = SkRect::MakeWH(50, 50);
120 
121     SkScalar unit = rand.nextUScalar1();
122     if (unit <= 0.3) {
123 //        SkDebugf("save\n");
124         canvas->save();
125     } else if (unit <= 0.6) {
126 //        SkDebugf("restore\n");
127         canvas->restore();
128     } else if (unit <= 0.9) {
129 //        SkDebugf("clip\n");
130         canvas->clipRect(rect);
131     } else {
132 //        SkDebugf("draw\n");
133         canvas->drawPaint(paint);
134     }
135 }
136 
137 #if SK_SUPPORT_GPU
138 
test_gpu_veto(skiatest::Reporter * reporter)139 static void test_gpu_veto(skiatest::Reporter* reporter) {
140     SkPictureRecorder recorder;
141 
142     SkCanvas* canvas = recorder.beginRecording(100, 100);
143     {
144         SkPath path;
145         path.moveTo(0, 0);
146         path.lineTo(50, 50);
147 
148         SkScalar intervals[] = { 1.0f, 1.0f };
149         SkAutoTUnref<SkPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0));
150 
151         SkPaint paint;
152         paint.setStyle(SkPaint::kStroke_Style);
153         paint.setPathEffect(dash);
154 
155         for (int i = 0; i < 50; ++i) {
156             canvas->drawPath(path, paint);
157         }
158     }
159     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
160     // path effects currently render an SkPicture undesireable for GPU rendering
161 
162     const char *reason = nullptr;
163     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr, &reason));
164     REPORTER_ASSERT(reporter, reason);
165 
166     canvas = recorder.beginRecording(100, 100);
167     {
168         SkPath path;
169 
170         path.moveTo(0, 0);
171         path.lineTo(0, 50);
172         path.lineTo(25, 25);
173         path.lineTo(50, 50);
174         path.lineTo(50, 0);
175         path.close();
176         REPORTER_ASSERT(reporter, !path.isConvex());
177 
178         SkPaint paint;
179         paint.setAntiAlias(true);
180         for (int i = 0; i < 50; ++i) {
181             canvas->drawPath(path, paint);
182         }
183     }
184     picture.reset(recorder.endRecording());
185     // A lot of small AA concave paths should be fine for GPU rendering
186     REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
187 
188     canvas = recorder.beginRecording(100, 100);
189     {
190         SkPath path;
191 
192         path.moveTo(0, 0);
193         path.lineTo(0, 100);
194         path.lineTo(50, 50);
195         path.lineTo(100, 100);
196         path.lineTo(100, 0);
197         path.close();
198         REPORTER_ASSERT(reporter, !path.isConvex());
199 
200         SkPaint paint;
201         paint.setAntiAlias(true);
202         for (int i = 0; i < 50; ++i) {
203             canvas->drawPath(path, paint);
204         }
205     }
206     picture.reset(recorder.endRecording());
207     // A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering
208     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
209 
210     canvas = recorder.beginRecording(100, 100);
211     {
212         SkPath path;
213 
214         path.moveTo(0, 0);
215         path.lineTo(0, 50);
216         path.lineTo(25, 25);
217         path.lineTo(50, 50);
218         path.lineTo(50, 0);
219         path.close();
220         REPORTER_ASSERT(reporter, !path.isConvex());
221 
222         SkPaint paint;
223         paint.setAntiAlias(true);
224         paint.setStyle(SkPaint::kStroke_Style);
225         paint.setStrokeWidth(0);
226         for (int i = 0; i < 50; ++i) {
227             canvas->drawPath(path, paint);
228         }
229     }
230     picture.reset(recorder.endRecording());
231     // hairline stroked AA concave paths are fine for GPU rendering
232     REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
233 
234     canvas = recorder.beginRecording(100, 100);
235     {
236         SkPaint paint;
237         SkScalar intervals [] = { 10, 20 };
238         SkPathEffect* pe = SkDashPathEffect::Create(intervals, 2, 25);
239         paint.setPathEffect(pe)->unref();
240 
241         SkPoint points [2] = { { 0, 0 }, { 100, 0 } };
242 
243         for (int i = 0; i < 50; ++i) {
244             canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint);
245         }
246     }
247     picture.reset(recorder.endRecording());
248     // fast-path dashed effects are fine for GPU rendering ...
249     REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
250 
251     canvas = recorder.beginRecording(100, 100);
252     {
253         SkPaint paint;
254         SkScalar intervals [] = { 10, 20 };
255         SkPathEffect* pe = SkDashPathEffect::Create(intervals, 2, 25);
256         paint.setPathEffect(pe)->unref();
257 
258         for (int i = 0; i < 50; ++i) {
259             canvas->drawRect(SkRect::MakeWH(10, 10), paint);
260         }
261     }
262     picture.reset(recorder.endRecording());
263     // ... but only when applied to drawPoint() calls
264     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
265 
266     // Nest the previous picture inside a new one.
267     canvas = recorder.beginRecording(100, 100);
268     {
269         canvas->drawPicture(picture.get());
270     }
271     picture.reset(recorder.endRecording());
272     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
273 }
274 
275 #endif
276 
test_savelayer_extraction(skiatest::Reporter * reporter)277 static void test_savelayer_extraction(skiatest::Reporter* reporter) {
278     static const int kWidth = 100;
279     static const int kHeight = 100;
280 
281     // Create complex paint that the bounding box computation code can't
282     // optimize away
283     SkScalar blueToRedMatrix[20] = { 0 };
284     blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
285     SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
286     SkAutoTUnref<SkImageFilter> filter(SkColorFilterImageFilter::Create(blueToRed.get()));
287 
288     SkPaint complexPaint;
289     complexPaint.setImageFilter(filter);
290 
291     SkAutoTUnref<SkPicture> pict, child;
292     SkRTreeFactory bbhFactory;
293 
294     {
295         SkPictureRecorder recorder;
296 
297         SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight),
298                                               &bbhFactory,
299                                               SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
300 
301         c->saveLayer(nullptr, &complexPaint);
302         c->restore();
303 
304         child.reset(recorder.endRecording());
305     }
306 
307     // create a picture with the structure:
308     // 1)
309     //      SaveLayer
310     //      Restore
311     // 2)
312     //      SaveLayer
313     //          Translate
314     //          SaveLayer w/ bound
315     //          Restore
316     //      Restore
317     // 3)
318     //      SaveLayer w/ copyable paint
319     //      Restore
320     // 4)
321     //      SaveLayer
322     //          DrawPicture (which has a SaveLayer/Restore pair)
323     //      Restore
324     // 5)
325     //      SaveLayer
326     //          DrawPicture with Matrix & Paint (with SaveLayer/Restore pair)
327     //      Restore
328     {
329         SkPictureRecorder recorder;
330 
331         SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth),
332                                               SkIntToScalar(kHeight),
333                                               &bbhFactory,
334                                               SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
335         // 1)
336         c->saveLayer(nullptr, &complexPaint); // layer #0
337         c->restore();
338 
339         // 2)
340         c->saveLayer(nullptr, nullptr); // layer #1
341             c->translate(kWidth / 2.0f, kHeight / 2.0f);
342             SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
343             c->saveLayer(&r, &complexPaint); // layer #2
344             c->restore();
345         c->restore();
346 
347         // 3)
348         {
349             c->saveLayer(nullptr, &complexPaint); // layer #3
350             c->restore();
351         }
352 
353         SkPaint layerPaint;
354         layerPaint.setColor(SK_ColorRED);  // Non-alpha only to avoid SaveLayerDrawRestoreNooper
355         // 4)
356         {
357             c->saveLayer(nullptr, &layerPaint);  // layer #4
358                 c->drawPicture(child);  // layer #5 inside picture
359             c->restore();
360         }
361         // 5
362         {
363             SkPaint picturePaint;
364             SkMatrix trans;
365             trans.setTranslate(10, 10);
366 
367             c->saveLayer(nullptr, &layerPaint);  // layer #6
368                 c->drawPicture(child, &trans, &picturePaint); // layer #7 inside picture
369             c->restore();
370         }
371 
372         pict.reset(recorder.endRecording());
373     }
374 
375     // Now test out the SaveLayer extraction
376     if (!SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds()) {
377         const SkBigPicture* bp = pict->asSkBigPicture();
378         REPORTER_ASSERT(reporter, bp);
379 
380         const SkBigPicture::AccelData* data = bp->accelData();
381         REPORTER_ASSERT(reporter, data);
382 
383         const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
384         REPORTER_ASSERT(reporter, 8 == gpuData->numBlocks());
385 
386         const SkLayerInfo::BlockInfo& info0 = gpuData->block(0);
387         // The parent/child layers appear in reverse order
388         const SkLayerInfo::BlockInfo& info1 = gpuData->block(2);
389         const SkLayerInfo::BlockInfo& info2 = gpuData->block(1);
390 
391         const SkLayerInfo::BlockInfo& info3 = gpuData->block(3);
392 
393         // The parent/child layers appear in reverse order
394         const SkLayerInfo::BlockInfo& info4 = gpuData->block(5);
395         const SkLayerInfo::BlockInfo& info5 = gpuData->block(4);
396 
397         // The parent/child layers appear in reverse order
398         const SkLayerInfo::BlockInfo& info6 = gpuData->block(7);
399         const SkLayerInfo::BlockInfo& info7 = gpuData->block(6);
400 
401         REPORTER_ASSERT(reporter, nullptr == info0.fPicture);
402         REPORTER_ASSERT(reporter, kWidth == info0.fBounds.width() &&
403                                   kHeight == info0.fBounds.height());
404         REPORTER_ASSERT(reporter, info0.fLocalMat.isIdentity());
405         REPORTER_ASSERT(reporter, info0.fPreMat.isIdentity());
406         REPORTER_ASSERT(reporter, 0 == info0.fBounds.fLeft && 0 == info0.fBounds.fTop);
407         REPORTER_ASSERT(reporter, nullptr != info0.fPaint);
408         REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
409 
410         REPORTER_ASSERT(reporter, nullptr == info1.fPicture);
411         REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.width() &&
412                                   kHeight/2.0 == info1.fBounds.height());
413         REPORTER_ASSERT(reporter, info1.fLocalMat.isIdentity());
414         REPORTER_ASSERT(reporter, info1.fPreMat.isIdentity());
415         REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.fLeft &&
416                                   kHeight/2.0 == info1.fBounds.fTop);
417         REPORTER_ASSERT(reporter, nullptr == info1.fPaint);
418         REPORTER_ASSERT(reporter, !info1.fIsNested &&
419                                   info1.fHasNestedLayers); // has a nested SL
420 
421         REPORTER_ASSERT(reporter, nullptr == info2.fPicture);
422         REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.width() &&
423                                   kHeight / 2 == info2.fBounds.height()); // bound reduces size
424         REPORTER_ASSERT(reporter, !info2.fLocalMat.isIdentity());
425         REPORTER_ASSERT(reporter, info2.fPreMat.isIdentity());
426         REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.fLeft &&   // translated
427                                   kHeight / 2 == info2.fBounds.fTop);
428         REPORTER_ASSERT(reporter, nullptr != info2.fPaint);
429         REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
430 
431         REPORTER_ASSERT(reporter, nullptr == info3.fPicture);
432         REPORTER_ASSERT(reporter, kWidth == info3.fBounds.width() &&
433                                   kHeight == info3.fBounds.height());
434         REPORTER_ASSERT(reporter, info3.fLocalMat.isIdentity());
435         REPORTER_ASSERT(reporter, info3.fPreMat.isIdentity());
436         REPORTER_ASSERT(reporter, 0 == info3.fBounds.fLeft && 0 == info3.fBounds.fTop);
437         REPORTER_ASSERT(reporter, info3.fPaint);
438         REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
439 
440         REPORTER_ASSERT(reporter, nullptr == info4.fPicture);
441         REPORTER_ASSERT(reporter, kWidth == info4.fBounds.width() &&
442                                   kHeight == info4.fBounds.height());
443         REPORTER_ASSERT(reporter, 0 == info4.fBounds.fLeft && 0 == info4.fBounds.fTop);
444         REPORTER_ASSERT(reporter, info4.fLocalMat.isIdentity());
445         REPORTER_ASSERT(reporter, info4.fPreMat.isIdentity());
446         REPORTER_ASSERT(reporter, info4.fPaint);
447         REPORTER_ASSERT(reporter, !info4.fIsNested &&
448                                   info4.fHasNestedLayers); // has a nested SL
449 
450         REPORTER_ASSERT(reporter, child == info5.fPicture); // in a child picture
451         REPORTER_ASSERT(reporter, kWidth == info5.fBounds.width() &&
452                                   kHeight == info5.fBounds.height());
453         REPORTER_ASSERT(reporter, 0 == info5.fBounds.fLeft && 0 == info5.fBounds.fTop);
454         REPORTER_ASSERT(reporter, info5.fLocalMat.isIdentity());
455         REPORTER_ASSERT(reporter, info5.fPreMat.isIdentity());
456         REPORTER_ASSERT(reporter, nullptr != info5.fPaint);
457         REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested
458 
459         REPORTER_ASSERT(reporter, nullptr == info6.fPicture);
460         REPORTER_ASSERT(reporter, kWidth-10 == info6.fBounds.width() &&
461                                   kHeight-10 == info6.fBounds.height());
462         REPORTER_ASSERT(reporter, 10 == info6.fBounds.fLeft && 10 == info6.fBounds.fTop);
463         REPORTER_ASSERT(reporter, info6.fLocalMat.isIdentity());
464         REPORTER_ASSERT(reporter, info6.fPreMat.isIdentity());
465         REPORTER_ASSERT(reporter, info6.fPaint);
466         REPORTER_ASSERT(reporter, !info6.fIsNested &&
467                                   info6.fHasNestedLayers); // has a nested SL
468 
469         REPORTER_ASSERT(reporter, child == info7.fPicture); // in a child picture
470         REPORTER_ASSERT(reporter, kWidth == info7.fBounds.width() &&
471                                   kHeight == info7.fBounds.height());
472         REPORTER_ASSERT(reporter, 0 == info7.fBounds.fLeft && 0 == info7.fBounds.fTop);
473         REPORTER_ASSERT(reporter, info7.fLocalMat.isIdentity());
474         REPORTER_ASSERT(reporter, info7.fPreMat.isIdentity());
475         REPORTER_ASSERT(reporter, nullptr != info7.fPaint);
476         REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested
477     }
478 }
479 
test_has_text(skiatest::Reporter * reporter)480 static void test_has_text(skiatest::Reporter* reporter) {
481     SkPictureRecorder recorder;
482 
483     SkCanvas* canvas = recorder.beginRecording(100,100);
484     {
485         canvas->drawRect(SkRect::MakeWH(20, 20), SkPaint());
486     }
487     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
488     REPORTER_ASSERT(reporter, !picture->hasText());
489 
490     SkPoint point = SkPoint::Make(10, 10);
491     canvas = recorder.beginRecording(100,100);
492     {
493         canvas->drawText("Q", 1, point.fX, point.fY, SkPaint());
494     }
495     picture.reset(recorder.endRecording());
496     REPORTER_ASSERT(reporter, picture->hasText());
497 
498     canvas = recorder.beginRecording(100,100);
499     {
500         canvas->drawPosText("Q", 1, &point, SkPaint());
501     }
502     picture.reset(recorder.endRecording());
503     REPORTER_ASSERT(reporter, picture->hasText());
504 
505     canvas = recorder.beginRecording(100,100);
506     {
507         canvas->drawPosTextH("Q", 1, &point.fX, point.fY, SkPaint());
508     }
509     picture.reset(recorder.endRecording());
510     REPORTER_ASSERT(reporter, picture->hasText());
511 
512     canvas = recorder.beginRecording(100,100);
513     {
514         SkPath path;
515         path.moveTo(0, 0);
516         path.lineTo(50, 50);
517 
518         canvas->drawTextOnPathHV("Q", 1, path, point.fX, point.fY, SkPaint());
519     }
520     picture.reset(recorder.endRecording());
521     REPORTER_ASSERT(reporter, picture->hasText());
522 
523     canvas = recorder.beginRecording(100,100);
524     {
525         SkPath path;
526         path.moveTo(0, 0);
527         path.lineTo(50, 50);
528 
529         canvas->drawTextOnPath("Q", 1, path, nullptr, SkPaint());
530     }
531     picture.reset(recorder.endRecording());
532     REPORTER_ASSERT(reporter, picture->hasText());
533 
534     // Nest the previous picture inside a new one.
535     canvas = recorder.beginRecording(100,100);
536     {
537         canvas->drawPicture(picture.get());
538     }
539     picture.reset(recorder.endRecording());
540     REPORTER_ASSERT(reporter, picture->hasText());
541 }
542 
set_canvas_to_save_count_4(SkCanvas * canvas)543 static void set_canvas_to_save_count_4(SkCanvas* canvas) {
544     canvas->restoreToCount(1);
545     canvas->save();
546     canvas->save();
547     canvas->save();
548 }
549 
550 /**
551  * A canvas that records the number of saves, saveLayers and restores.
552  */
553 class SaveCountingCanvas : public SkCanvas {
554 public:
SaveCountingCanvas(int width,int height)555     SaveCountingCanvas(int width, int height)
556         : INHERITED(width, height)
557         , fSaveCount(0)
558         , fSaveLayerCount(0)
559         , fRestoreCount(0){
560     }
561 
getSaveLayerStrategy(const SaveLayerRec & rec)562     SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
563         ++fSaveLayerCount;
564         return this->INHERITED::getSaveLayerStrategy(rec);
565     }
566 
willSave()567     void willSave() override {
568         ++fSaveCount;
569         this->INHERITED::willSave();
570     }
571 
willRestore()572     void willRestore() override {
573         ++fRestoreCount;
574         this->INHERITED::willRestore();
575     }
576 
getSaveCount() const577     unsigned int getSaveCount() const { return fSaveCount; }
getSaveLayerCount() const578     unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
getRestoreCount() const579     unsigned int getRestoreCount() const { return fRestoreCount; }
580 
581 private:
582     unsigned int fSaveCount;
583     unsigned int fSaveLayerCount;
584     unsigned int fRestoreCount;
585 
586     typedef SkCanvas INHERITED;
587 };
588 
check_save_state(skiatest::Reporter * reporter,SkPicture * picture,unsigned int numSaves,unsigned int numSaveLayers,unsigned int numRestores)589 void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
590                       unsigned int numSaves, unsigned int numSaveLayers,
591                       unsigned int numRestores) {
592     SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
593                               SkScalarCeilToInt(picture->cullRect().height()));
594 
595     picture->playback(&canvas);
596 
597     // Optimizations may have removed these,
598     // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
599     REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
600     REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
601     REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
602 }
603 
604 // This class exists so SkPicture can friend it and give it access to
605 // the 'partialReplay' method.
606 class SkPictureRecorderReplayTester {
607 public:
Copy(SkPictureRecorder * recorder)608     static SkPicture* Copy(SkPictureRecorder* recorder) {
609         SkPictureRecorder recorder2;
610 
611         SkCanvas* canvas = recorder2.beginRecording(10, 10);
612 
613         recorder->partialReplay(canvas);
614 
615         return recorder2.endRecording();
616     }
617 };
618 
create_imbalance(SkCanvas * canvas)619 static void create_imbalance(SkCanvas* canvas) {
620     SkRect clipRect = SkRect::MakeWH(2, 2);
621     SkRect drawRect = SkRect::MakeWH(10, 10);
622     canvas->save();
623         canvas->clipRect(clipRect, SkRegion::kReplace_Op);
624         canvas->translate(1.0f, 1.0f);
625         SkPaint p;
626         p.setColor(SK_ColorGREEN);
627         canvas->drawRect(drawRect, p);
628     // no restore
629 }
630 
631 // This tests that replaying a potentially unbalanced picture into a canvas
632 // doesn't affect the canvas' save count or matrix/clip state.
check_balance(skiatest::Reporter * reporter,SkPicture * picture)633 static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
634     SkBitmap bm;
635     bm.allocN32Pixels(4, 3);
636     SkCanvas canvas(bm);
637 
638     int beforeSaveCount = canvas.getSaveCount();
639 
640     SkMatrix beforeMatrix = canvas.getTotalMatrix();
641 
642     SkRect beforeClip;
643 
644     canvas.getClipBounds(&beforeClip);
645 
646     canvas.drawPicture(picture);
647 
648     REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
649     REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
650 
651     SkRect afterClip;
652 
653     canvas.getClipBounds(&afterClip);
654 
655     REPORTER_ASSERT(reporter, afterClip == beforeClip);
656 }
657 
658 // Test out SkPictureRecorder::partialReplay
DEF_TEST(PictureRecorder_replay,reporter)659 DEF_TEST(PictureRecorder_replay, reporter) {
660     // check save/saveLayer state
661     {
662         SkPictureRecorder recorder;
663 
664         SkCanvas* canvas = recorder.beginRecording(10, 10);
665 
666         canvas->saveLayer(nullptr, nullptr);
667 
668         SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
669 
670         // The extra save and restore comes from the Copy process.
671         check_save_state(reporter, copy, 2, 1, 3);
672 
673         canvas->saveLayer(nullptr, nullptr);
674 
675         SkAutoTUnref<SkPicture> final(recorder.endRecording());
676 
677         check_save_state(reporter, final, 1, 2, 3);
678 
679         // The copy shouldn't pick up any operations added after it was made
680         check_save_state(reporter, copy, 2, 1, 3);
681     }
682 
683     // (partially) check leakage of draw ops
684     {
685         SkPictureRecorder recorder;
686 
687         SkCanvas* canvas = recorder.beginRecording(10, 10);
688 
689         SkRect r = SkRect::MakeWH(5, 5);
690         SkPaint p;
691 
692         canvas->drawRect(r, p);
693 
694         SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
695 
696         REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
697 
698         SkBitmap bm;
699         make_bm(&bm, 10, 10, SK_ColorRED, true);
700 
701         r.offset(5.0f, 5.0f);
702         canvas->drawBitmapRect(bm, r, nullptr);
703 
704         SkAutoTUnref<SkPicture> final(recorder.endRecording());
705         REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
706 
707         REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
708 
709         // The snapshot shouldn't pick up any operations added after it was made
710         REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
711     }
712 
713     // Recreate the Android partialReplay test case
714     {
715         SkPictureRecorder recorder;
716 
717         SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
718         create_imbalance(canvas);
719 
720         int expectedSaveCount = canvas->getSaveCount();
721 
722         SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
723         check_balance(reporter, copy);
724 
725         REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
726 
727         // End the recording of source to test the picture finalization
728         // process isn't complicated by the partialReplay step
729         SkAutoTUnref<SkPicture> final(recorder.endRecording());
730     }
731 }
732 
test_unbalanced_save_restores(skiatest::Reporter * reporter)733 static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
734     SkCanvas testCanvas(100, 100);
735     set_canvas_to_save_count_4(&testCanvas);
736 
737     REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
738 
739     SkPaint paint;
740     SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
741 
742     SkPictureRecorder recorder;
743 
744     {
745         // Create picture with 2 unbalanced saves
746         SkCanvas* canvas = recorder.beginRecording(100, 100);
747         canvas->save();
748         canvas->translate(10, 10);
749         canvas->drawRect(rect, paint);
750         canvas->save();
751         canvas->translate(10, 10);
752         canvas->drawRect(rect, paint);
753         SkAutoTUnref<SkPicture> extraSavePicture(recorder.endRecording());
754 
755         testCanvas.drawPicture(extraSavePicture);
756         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
757     }
758 
759     set_canvas_to_save_count_4(&testCanvas);
760 
761     {
762         // Create picture with 2 unbalanced restores
763         SkCanvas* canvas = recorder.beginRecording(100, 100);
764         canvas->save();
765         canvas->translate(10, 10);
766         canvas->drawRect(rect, paint);
767         canvas->save();
768         canvas->translate(10, 10);
769         canvas->drawRect(rect, paint);
770         canvas->restore();
771         canvas->restore();
772         canvas->restore();
773         canvas->restore();
774         SkAutoTUnref<SkPicture> extraRestorePicture(recorder.endRecording());
775 
776         testCanvas.drawPicture(extraRestorePicture);
777         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
778     }
779 
780     set_canvas_to_save_count_4(&testCanvas);
781 
782     {
783         SkCanvas* canvas = recorder.beginRecording(100, 100);
784         canvas->translate(10, 10);
785         canvas->drawRect(rect, paint);
786         SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording());
787 
788         testCanvas.drawPicture(noSavePicture);
789         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
790         REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
791     }
792 }
793 
test_peephole()794 static void test_peephole() {
795     SkRandom rand;
796 
797     SkPictureRecorder recorder;
798 
799     for (int j = 0; j < 100; j++) {
800         SkRandom rand2(rand); // remember the seed
801 
802         SkCanvas* canvas = recorder.beginRecording(100, 100);
803 
804         for (int i = 0; i < 1000; ++i) {
805             rand_op(canvas, rand);
806         }
807         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
808 
809         rand = rand2;
810     }
811 
812     {
813         SkCanvas* canvas = recorder.beginRecording(100, 100);
814         SkRect rect = SkRect::MakeWH(50, 50);
815 
816         for (int i = 0; i < 100; ++i) {
817             canvas->save();
818         }
819         while (canvas->getSaveCount() > 1) {
820             canvas->clipRect(rect);
821             canvas->restore();
822         }
823         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
824     }
825 }
826 
827 #ifndef SK_DEBUG
828 // Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
829 // should never do this.
test_bad_bitmap()830 static void test_bad_bitmap() {
831     // This bitmap has a width and height but no pixels. As a result, attempting to record it will
832     // fail.
833     SkBitmap bm;
834     bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
835     SkPictureRecorder recorder;
836     SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
837     recordingCanvas->drawBitmap(bm, 0, 0);
838     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
839 
840     SkCanvas canvas;
841     canvas.drawPicture(picture);
842 }
843 #endif
844 
serialized_picture_from_bitmap(const SkBitmap & bitmap)845 static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
846     SkPictureRecorder recorder;
847     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bitmap.width()),
848                                                SkIntToScalar(bitmap.height()));
849     canvas->drawBitmap(bitmap, 0, 0);
850     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
851 
852     SkDynamicMemoryWStream wStream;
853     SkAutoTUnref<SkPixelSerializer> serializer(
854             SkImageEncoder::CreatePixelSerializer());
855     picture->serialize(&wStream, serializer);
856     return wStream.copyToData();
857 }
858 
859 struct ErrorContext {
860     int fErrors;
861     skiatest::Reporter* fReporter;
862 };
863 
assert_one_parse_error_cb(SkError error,void * context)864 static void assert_one_parse_error_cb(SkError error, void* context) {
865     ErrorContext* errorContext = static_cast<ErrorContext*>(context);
866     errorContext->fErrors++;
867     // This test only expects one error, and that is a kParseError. If there are others,
868     // there is some unknown problem.
869     REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors,
870                             "This threw more errors than expected.");
871     REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error,
872                             SkGetLastErrorString());
873 }
874 
md5(const SkBitmap & bm,SkMD5::Digest * digest)875 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) {
876     SkAutoLockPixels autoLockPixels(bm);
877     SkASSERT(bm.getPixels());
878     SkMD5 md5;
879     size_t rowLen = bm.info().bytesPerPixel() * bm.width();
880     for (int y = 0; y < bm.height(); ++y) {
881         md5.update(static_cast<uint8_t*>(bm.getAddr(0, y)), rowLen);
882     }
883     md5.finish(*digest);
884 }
885 
DEF_TEST(Picture_EncodedData,reporter)886 DEF_TEST(Picture_EncodedData, reporter) {
887     // Create a bitmap that will be encoded.
888     SkBitmap original;
889     make_bm(&original, 100, 100, SK_ColorBLUE, true);
890     SkDynamicMemoryWStream wStream;
891     if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
892         return;
893     }
894     SkAutoDataUnref data(wStream.copyToData());
895 
896     SkBitmap bm;
897     bool installSuccess = SkDEPRECATED_InstallDiscardablePixelRef(data, &bm);
898     REPORTER_ASSERT(reporter, installSuccess);
899 
900     // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
901     // Flattening original will follow the old path of performing an encode, while flattening bm
902     // will use the already encoded data.
903     SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
904     SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
905     REPORTER_ASSERT(reporter, picture1->equals(picture2));
906 
907     // Now test that a parse error was generated when trying to create a new SkPicture without
908     // providing a function to decode the bitmap.
909     ErrorContext context;
910     context.fErrors = 0;
911     context.fReporter = reporter;
912     SkSetErrorCallback(assert_one_parse_error_cb, &context);
913     SkMemoryStream pictureStream(picture1);
914     SkClearLastError();
915     SkAutoTUnref<SkPicture> pictureFromStream(SkPicture::CreateFromStream(&pictureStream, nullptr));
916     REPORTER_ASSERT(reporter, pictureFromStream.get() != nullptr);
917     SkClearLastError();
918     SkSetErrorCallback(nullptr, nullptr);
919 
920     // Test that using the version of CreateFromStream that just takes a stream also decodes the
921     // bitmap. Drawing this picture should look exactly like the original bitmap.
922     SkMD5::Digest referenceDigest;
923     md5(original, &referenceDigest);
924 
925     SkBitmap dst;
926     dst.allocPixels(original.info());
927     dst.eraseColor(SK_ColorRED);
928     SkCanvas canvas(dst);
929 
930     pictureStream.rewind();
931     pictureFromStream.reset(SkPicture::CreateFromStream(&pictureStream));
932     canvas.drawPicture(pictureFromStream.get());
933 
934     SkMD5::Digest digest2;
935     md5(dst, &digest2);
936     REPORTER_ASSERT(reporter, referenceDigest == digest2);
937 }
938 
test_clip_bound_opt(skiatest::Reporter * reporter)939 static void test_clip_bound_opt(skiatest::Reporter* reporter) {
940     // Test for crbug.com/229011
941     SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
942                                     SkIntToScalar(2), SkIntToScalar(2));
943     SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
944                                     SkIntToScalar(1), SkIntToScalar(1));
945     SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
946                                     SkIntToScalar(1), SkIntToScalar(1));
947 
948     SkPath invPath;
949     invPath.addOval(rect1);
950     invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
951     SkPath path;
952     path.addOval(rect2);
953     SkPath path2;
954     path2.addOval(rect3);
955     SkIRect clipBounds;
956     SkPictureRecorder recorder;
957 
958     // Testing conservative-raster-clip that is enabled by PictureRecord
959     {
960         SkCanvas* canvas = recorder.beginRecording(10, 10);
961         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
962         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
963         REPORTER_ASSERT(reporter, true == nonEmpty);
964         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
965         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
966         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
967         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
968     }
969     {
970         SkCanvas* canvas = recorder.beginRecording(10, 10);
971         canvas->clipPath(path, SkRegion::kIntersect_Op);
972         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
973         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
974         REPORTER_ASSERT(reporter, true == nonEmpty);
975         REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
976         REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
977         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
978         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
979     }
980     {
981         SkCanvas* canvas = recorder.beginRecording(10, 10);
982         canvas->clipPath(path, SkRegion::kIntersect_Op);
983         canvas->clipPath(invPath, SkRegion::kUnion_Op);
984         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
985         REPORTER_ASSERT(reporter, true == nonEmpty);
986         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
987         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
988         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
989         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
990     }
991     {
992         SkCanvas* canvas = recorder.beginRecording(10, 10);
993         canvas->clipPath(path, SkRegion::kDifference_Op);
994         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
995         REPORTER_ASSERT(reporter, true == nonEmpty);
996         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
997         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
998         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
999         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
1000     }
1001     {
1002         SkCanvas* canvas = recorder.beginRecording(10, 10);
1003         canvas->clipPath(path, SkRegion::kReverseDifference_Op);
1004         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1005         // True clip is actually empty in this case, but the best
1006         // determination we can make using only bounds as input is that the
1007         // clip is included in the bounds of 'path'.
1008         REPORTER_ASSERT(reporter, true == nonEmpty);
1009         REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
1010         REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
1011         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1012         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1013     }
1014     {
1015         SkCanvas* canvas = recorder.beginRecording(10, 10);
1016         canvas->clipPath(path, SkRegion::kIntersect_Op);
1017         canvas->clipPath(path2, SkRegion::kXOR_Op);
1018         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1019         REPORTER_ASSERT(reporter, true == nonEmpty);
1020         REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
1021         REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
1022         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1023         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1024     }
1025 }
1026 
test_cull_rect_reset(skiatest::Reporter * reporter)1027 static void test_cull_rect_reset(skiatest::Reporter* reporter) {
1028     SkPictureRecorder recorder;
1029     SkRect bounds = SkRect::MakeWH(10, 10);
1030     SkRTreeFactory factory;
1031     SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
1032     bounds = SkRect::MakeWH(100, 100);
1033     SkPaint paint;
1034     canvas->drawRect(bounds, paint);
1035     canvas->drawRect(bounds, paint);
1036     SkAutoTUnref<const SkPicture> p(recorder.endRecordingAsPicture(bounds));
1037     const SkBigPicture* picture = p->asSkBigPicture();
1038     REPORTER_ASSERT(reporter, picture);
1039 
1040     SkRect finalCullRect = picture->cullRect();
1041     REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
1042     REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
1043     REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
1044     REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
1045 
1046     const SkBBoxHierarchy* pictureBBH = picture->bbh();
1047     SkRect bbhCullRect = pictureBBH->getRootBound();
1048     REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
1049     REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
1050     REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
1051     REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
1052 }
1053 
1054 
1055 /**
1056  * A canvas that records the number of clip commands.
1057  */
1058 class ClipCountingCanvas : public SkCanvas {
1059 public:
ClipCountingCanvas(int width,int height)1060     ClipCountingCanvas(int width, int height)
1061         : INHERITED(width, height)
1062         , fClipCount(0){
1063     }
1064 
onClipRect(const SkRect & r,SkRegion::Op op,ClipEdgeStyle edgeStyle)1065     virtual void onClipRect(const SkRect& r,
1066                             SkRegion::Op op,
1067                             ClipEdgeStyle edgeStyle) override {
1068         fClipCount += 1;
1069         this->INHERITED::onClipRect(r, op, edgeStyle);
1070     }
1071 
onClipRRect(const SkRRect & rrect,SkRegion::Op op,ClipEdgeStyle edgeStyle)1072     virtual void onClipRRect(const SkRRect& rrect,
1073                              SkRegion::Op op,
1074                              ClipEdgeStyle edgeStyle)override {
1075         fClipCount += 1;
1076         this->INHERITED::onClipRRect(rrect, op, edgeStyle);
1077     }
1078 
onClipPath(const SkPath & path,SkRegion::Op op,ClipEdgeStyle edgeStyle)1079     virtual void onClipPath(const SkPath& path,
1080                             SkRegion::Op op,
1081                             ClipEdgeStyle edgeStyle) override {
1082         fClipCount += 1;
1083         this->INHERITED::onClipPath(path, op, edgeStyle);
1084     }
1085 
onClipRegion(const SkRegion & deviceRgn,SkRegion::Op op)1086     void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override {
1087         fClipCount += 1;
1088         this->INHERITED::onClipRegion(deviceRgn, op);
1089     }
1090 
getClipCount() const1091     unsigned getClipCount() const { return fClipCount; }
1092 
1093 private:
1094     unsigned fClipCount;
1095 
1096     typedef SkCanvas INHERITED;
1097 };
1098 
test_clip_expansion(skiatest::Reporter * reporter)1099 static void test_clip_expansion(skiatest::Reporter* reporter) {
1100     SkPictureRecorder recorder;
1101     SkCanvas* canvas = recorder.beginRecording(10, 10);
1102 
1103     canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
1104     // The following expanding clip should not be skipped.
1105     canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
1106     // Draw something so the optimizer doesn't just fold the world.
1107     SkPaint p;
1108     p.setColor(SK_ColorBLUE);
1109     canvas->drawPaint(p);
1110     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1111 
1112     ClipCountingCanvas testCanvas(10, 10);
1113     picture->playback(&testCanvas);
1114 
1115     // Both clips should be present on playback.
1116     REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
1117 }
1118 
test_hierarchical(skiatest::Reporter * reporter)1119 static void test_hierarchical(skiatest::Reporter* reporter) {
1120     SkBitmap bm;
1121     make_bm(&bm, 10, 10, SK_ColorRED, true);
1122 
1123     SkPictureRecorder recorder;
1124 
1125     recorder.beginRecording(10, 10);
1126     SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
1127     REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
1128 
1129     recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
1130     SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
1131     REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
1132 
1133     {
1134         SkCanvas* canvas = recorder.beginRecording(10, 10);
1135         canvas->drawPicture(childPlain);
1136         SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
1137         REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
1138     }
1139     {
1140         SkCanvas* canvas = recorder.beginRecording(10, 10);
1141         canvas->drawPicture(childWithBitmap);
1142         SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
1143         REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
1144     }
1145     {
1146         SkCanvas* canvas = recorder.beginRecording(10, 10);
1147         canvas->drawBitmap(bm, 0, 0);
1148         canvas->drawPicture(childPlain);
1149         SkAutoTUnref<SkPicture> parentWBP(recorder.endRecording());
1150         REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
1151     }
1152     {
1153         SkCanvas* canvas = recorder.beginRecording(10, 10);
1154         canvas->drawBitmap(bm, 0, 0);
1155         canvas->drawPicture(childWithBitmap);
1156         SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
1157         REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
1158     }
1159 }
1160 
test_gen_id(skiatest::Reporter * reporter)1161 static void test_gen_id(skiatest::Reporter* reporter) {
1162 
1163     SkPictureRecorder recorder;
1164     recorder.beginRecording(0, 0);
1165     SkAutoTUnref<SkPicture> empty(recorder.endRecording());
1166 
1167     // Empty pictures should still have a valid ID
1168     REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
1169 
1170     SkCanvas* canvas = recorder.beginRecording(1, 1);
1171     canvas->drawARGB(255, 255, 255, 255);
1172     SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
1173     // picture should have a non-zero id after recording
1174     REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
1175 
1176     // both pictures should have different ids
1177     REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
1178 }
1179 
test_typeface(skiatest::Reporter * reporter)1180 static void test_typeface(skiatest::Reporter* reporter) {
1181     SkPictureRecorder recorder;
1182     SkCanvas* canvas = recorder.beginRecording(10, 10);
1183     SkPaint paint;
1184     paint.setTypeface(SkTypeface::CreateFromName("Arial", SkTypeface::kItalic));
1185     canvas->drawText("Q", 1, 0, 10, paint);
1186     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1187     REPORTER_ASSERT(reporter, picture->hasText());
1188     SkDynamicMemoryWStream stream;
1189     picture->serialize(&stream);
1190 }
1191 
DEF_TEST(Picture,reporter)1192 DEF_TEST(Picture, reporter) {
1193     test_typeface(reporter);
1194 #ifdef SK_DEBUG
1195     test_deleting_empty_picture();
1196     test_serializing_empty_picture();
1197 #else
1198     test_bad_bitmap();
1199 #endif
1200     test_unbalanced_save_restores(reporter);
1201     test_peephole();
1202 #if SK_SUPPORT_GPU
1203     test_gpu_veto(reporter);
1204 #endif
1205     test_has_text(reporter);
1206     test_images_are_found_by_willPlayBackBitmaps(reporter);
1207     test_analysis(reporter);
1208     test_clip_bound_opt(reporter);
1209     test_clip_expansion(reporter);
1210     test_hierarchical(reporter);
1211     test_gen_id(reporter);
1212     test_savelayer_extraction(reporter);
1213     test_cull_rect_reset(reporter);
1214 }
1215 
draw_bitmaps(const SkBitmap bitmap,SkCanvas * canvas)1216 static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
1217     const SkPaint paint;
1218     const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
1219     const SkIRect irect =  { 2, 2, 3, 3 };
1220 
1221     // Don't care what these record, as long as they're legal.
1222     canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
1223     canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
1224     canvas->drawBitmapNine(bitmap, irect, rect, &paint);
1225     canvas->drawBitmap(bitmap, 1, 1);   // drawSprite
1226 }
1227 
test_draw_bitmaps(SkCanvas * canvas)1228 static void test_draw_bitmaps(SkCanvas* canvas) {
1229     SkBitmap empty;
1230     draw_bitmaps(empty, canvas);
1231     empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
1232     draw_bitmaps(empty, canvas);
1233 }
1234 
DEF_TEST(Picture_EmptyBitmap,r)1235 DEF_TEST(Picture_EmptyBitmap, r) {
1236     SkPictureRecorder recorder;
1237     test_draw_bitmaps(recorder.beginRecording(10, 10));
1238     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1239 }
1240 
DEF_TEST(Canvas_EmptyBitmap,r)1241 DEF_TEST(Canvas_EmptyBitmap, r) {
1242     SkBitmap dst;
1243     dst.allocN32Pixels(10, 10);
1244     SkCanvas canvas(dst);
1245 
1246     test_draw_bitmaps(&canvas);
1247 }
1248 
DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore,reporter)1249 DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
1250     // This test is from crbug.com/344987.
1251     // The commands are:
1252     //   saveLayer with paint that modifies alpha
1253     //     drawBitmapRect
1254     //     drawBitmapRect
1255     //   restore
1256     // The bug was that this structure was modified so that:
1257     //  - The saveLayer and restore were eliminated
1258     //  - The alpha was only applied to the first drawBitmapRectToRect
1259 
1260     // This test draws blue and red squares inside a 50% transparent
1261     // layer.  Both colours should show up muted.
1262     // When the bug is present, the red square (the second bitmap)
1263     // shows upwith full opacity.
1264 
1265     SkBitmap blueBM;
1266     make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
1267     SkBitmap redBM;
1268     make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
1269     SkPaint semiTransparent;
1270     semiTransparent.setAlpha(0x80);
1271 
1272     SkPictureRecorder recorder;
1273     SkCanvas* canvas = recorder.beginRecording(100, 100);
1274     canvas->drawARGB(0, 0, 0, 0);
1275 
1276     canvas->saveLayer(0, &semiTransparent);
1277     canvas->drawBitmap(blueBM, 25, 25);
1278     canvas->drawBitmap(redBM, 50, 50);
1279     canvas->restore();
1280 
1281     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1282 
1283     // Now replay the picture back on another canvas
1284     // and check a couple of its pixels.
1285     SkBitmap replayBM;
1286     make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
1287     SkCanvas replayCanvas(replayBM);
1288     picture->playback(&replayCanvas);
1289     replayCanvas.flush();
1290 
1291     // With the bug present, at (55, 55) we would get a fully opaque red
1292     // intead of a dark red.
1293     REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
1294     REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
1295 }
1296 
1297 struct CountingBBH : public SkBBoxHierarchy {
1298     mutable int searchCalls;
1299     SkRect rootBound;
1300 
CountingBBHCountingBBH1301     CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
1302 
searchCountingBBH1303     void search(const SkRect& query, SkTDArray<int>* results) const override {
1304         this->searchCalls++;
1305     }
1306 
insertCountingBBH1307     void insert(const SkRect[], int) override {}
bytesUsedCountingBBH1308     virtual size_t bytesUsed() const override { return 0; }
getRootBoundCountingBBH1309     SkRect getRootBound() const override { return rootBound; }
1310 };
1311 
1312 class SpoonFedBBHFactory : public SkBBHFactory {
1313 public:
SpoonFedBBHFactory(SkBBoxHierarchy * bbh)1314     explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
operator ()(const SkRect &) const1315     SkBBoxHierarchy* operator()(const SkRect&) const override {
1316         return SkRef(fBBH);
1317     }
1318 private:
1319     SkBBoxHierarchy* fBBH;
1320 };
1321 
1322 // When the canvas clip covers the full picture, we don't need to call the BBH.
DEF_TEST(Picture_SkipBBH,r)1323 DEF_TEST(Picture_SkipBBH, r) {
1324     SkRect bound = SkRect::MakeWH(320, 240);
1325     CountingBBH bbh(bound);
1326     SpoonFedBBHFactory factory(&bbh);
1327 
1328     SkPictureRecorder recorder;
1329     SkCanvas* c = recorder.beginRecording(bound, &factory);
1330     // Record a few ops so we don't hit a small- or empty- picture optimization.
1331         c->drawRect(bound, SkPaint());
1332         c->drawRect(bound, SkPaint());
1333     SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
1334 
1335     SkCanvas big(640, 480), small(300, 200);
1336 
1337     picture->playback(&big);
1338     REPORTER_ASSERT(r, bbh.searchCalls == 0);
1339 
1340     picture->playback(&small);
1341     REPORTER_ASSERT(r, bbh.searchCalls == 1);
1342 }
1343 
DEF_TEST(Picture_BitmapLeak,r)1344 DEF_TEST(Picture_BitmapLeak, r) {
1345     SkBitmap mut, immut;
1346     mut.allocN32Pixels(300, 200);
1347     immut.allocN32Pixels(300, 200);
1348     immut.setImmutable();
1349     SkASSERT(!mut.isImmutable());
1350     SkASSERT(immut.isImmutable());
1351 
1352     // No one can hold a ref on our pixels yet.
1353     REPORTER_ASSERT(r, mut.pixelRef()->unique());
1354     REPORTER_ASSERT(r, immut.pixelRef()->unique());
1355 
1356     SkAutoTUnref<const SkPicture> pic;
1357     {
1358         // we want the recorder to go out of scope before our subsequent checks, so we
1359         // place it inside local braces.
1360         SkPictureRecorder rec;
1361         SkCanvas* canvas = rec.beginRecording(1920, 1200);
1362             canvas->drawBitmap(mut, 0, 0);
1363             canvas->drawBitmap(immut, 800, 600);
1364         pic.reset(rec.endRecording());
1365     }
1366 
1367     // The picture shares the immutable pixels but copies the mutable ones.
1368     REPORTER_ASSERT(r, mut.pixelRef()->unique());
1369     REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1370 
1371     // When the picture goes away, it's just our bitmaps holding the refs.
1372     pic.reset(nullptr);
1373     REPORTER_ASSERT(r, mut.pixelRef()->unique());
1374     REPORTER_ASSERT(r, immut.pixelRef()->unique());
1375 }
1376 
1377 // getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
DEF_TEST(Picture_getRecordingCanvas,r)1378 DEF_TEST(Picture_getRecordingCanvas, r) {
1379     SkPictureRecorder rec;
1380     REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1381     for (int i = 0; i < 3; i++) {
1382         rec.beginRecording(100, 100);
1383         REPORTER_ASSERT(r, rec.getRecordingCanvas());
1384         rec.endRecording()->unref();
1385         REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1386     }
1387 }
1388 
DEF_TEST(MiniRecorderLeftHanging,r)1389 DEF_TEST(MiniRecorderLeftHanging, r) {
1390     // Any shader or other ref-counted effect will do just fine here.
1391     SkPaint paint;
1392     paint.setShader(SkShader::CreateColorShader(SK_ColorRED))->unref();
1393 
1394     SkMiniRecorder rec;
1395     REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
1396     // Don't call rec.detachPicture().  Test succeeds by not asserting or leaking the shader.
1397 }
1398 
DEF_TEST(Picture_preserveCullRect,r)1399 DEF_TEST(Picture_preserveCullRect, r) {
1400     SkPictureRecorder recorder;
1401 
1402     SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
1403     c->clear(SK_ColorCYAN);
1404 
1405     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1406     SkDynamicMemoryWStream wstream;
1407     picture->serialize(&wstream);
1408 
1409     SkAutoTDelete<SkStream> rstream(wstream.detachAsStream());
1410     SkAutoTUnref<SkPicture> deserializedPicture(SkPicture::CreateFromStream(rstream));
1411 
1412     REPORTER_ASSERT(r, SkToBool(deserializedPicture));
1413     REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
1414     REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
1415     REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
1416     REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
1417 }
1418