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