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