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