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