PictureTest.cpp revision 15877b6eae33a9282458bdb904a6d00440eca0ec
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
987/**
988 * A canvas that records the number of clip commands.
989 */
990class ClipCountingCanvas : public SkCanvas {
991public:
992    ClipCountingCanvas(int width, int height)
993        : INHERITED(width, height)
994        , fClipCount(0){
995    }
996
997    virtual void onClipRect(const SkRect& r,
998                            SkRegion::Op op,
999                            ClipEdgeStyle edgeStyle) override {
1000        fClipCount += 1;
1001        this->INHERITED::onClipRect(r, op, edgeStyle);
1002    }
1003
1004    virtual void onClipRRect(const SkRRect& rrect,
1005                             SkRegion::Op op,
1006                             ClipEdgeStyle edgeStyle)override {
1007        fClipCount += 1;
1008        this->INHERITED::onClipRRect(rrect, op, edgeStyle);
1009    }
1010
1011    virtual void onClipPath(const SkPath& path,
1012                            SkRegion::Op op,
1013                            ClipEdgeStyle edgeStyle) override {
1014        fClipCount += 1;
1015        this->INHERITED::onClipPath(path, op, edgeStyle);
1016    }
1017
1018    void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override {
1019        fClipCount += 1;
1020        this->INHERITED::onClipRegion(deviceRgn, op);
1021    }
1022
1023    unsigned getClipCount() const { return fClipCount; }
1024
1025private:
1026    unsigned fClipCount;
1027
1028    typedef SkCanvas INHERITED;
1029};
1030
1031static void test_clip_expansion(skiatest::Reporter* reporter) {
1032    SkPictureRecorder recorder;
1033    SkCanvas* canvas = recorder.beginRecording(10, 10);
1034
1035    canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
1036    // The following expanding clip should not be skipped.
1037    canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
1038    // Draw something so the optimizer doesn't just fold the world.
1039    SkPaint p;
1040    p.setColor(SK_ColorBLUE);
1041    canvas->drawPaint(p);
1042    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1043
1044    ClipCountingCanvas testCanvas(10, 10);
1045    picture->playback(&testCanvas);
1046
1047    // Both clips should be present on playback.
1048    REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
1049}
1050
1051static void test_hierarchical(skiatest::Reporter* reporter) {
1052    SkBitmap bm;
1053    make_bm(&bm, 10, 10, SK_ColorRED, true);
1054
1055    SkPictureRecorder recorder;
1056
1057    recorder.beginRecording(10, 10);
1058    SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
1059    REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
1060
1061    recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
1062    SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
1063    REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
1064
1065    {
1066        SkCanvas* canvas = recorder.beginRecording(10, 10);
1067        canvas->drawPicture(childPlain);
1068        SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
1069        REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
1070    }
1071    {
1072        SkCanvas* canvas = recorder.beginRecording(10, 10);
1073        canvas->drawPicture(childWithBitmap);
1074        SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
1075        REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
1076    }
1077    {
1078        SkCanvas* canvas = recorder.beginRecording(10, 10);
1079        canvas->drawBitmap(bm, 0, 0);
1080        canvas->drawPicture(childPlain);
1081        SkAutoTUnref<SkPicture> parentWBP(recorder.endRecording());
1082        REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
1083    }
1084    {
1085        SkCanvas* canvas = recorder.beginRecording(10, 10);
1086        canvas->drawBitmap(bm, 0, 0);
1087        canvas->drawPicture(childWithBitmap);
1088        SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
1089        REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
1090    }
1091}
1092
1093static void test_gen_id(skiatest::Reporter* reporter) {
1094
1095    SkPictureRecorder recorder;
1096    recorder.beginRecording(0, 0);
1097    SkAutoTUnref<SkPicture> empty(recorder.endRecording());
1098
1099    // Empty pictures should still have a valid ID
1100    REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
1101
1102    SkCanvas* canvas = recorder.beginRecording(1, 1);
1103    canvas->drawARGB(255, 255, 255, 255);
1104    SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
1105    // picture should have a non-zero id after recording
1106    REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
1107
1108    // both pictures should have different ids
1109    REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
1110}
1111
1112DEF_TEST(Picture, reporter) {
1113#ifdef SK_DEBUG
1114    test_deleting_empty_picture();
1115    test_serializing_empty_picture();
1116#else
1117    test_bad_bitmap();
1118#endif
1119    test_unbalanced_save_restores(reporter);
1120    test_peephole();
1121#if SK_SUPPORT_GPU
1122    test_gpu_veto(reporter);
1123#endif
1124    test_has_text(reporter);
1125    test_analysis(reporter);
1126    test_bitmap_with_encoded_data(reporter);
1127    test_clip_bound_opt(reporter);
1128    test_clip_expansion(reporter);
1129    test_hierarchical(reporter);
1130    test_gen_id(reporter);
1131    test_savelayer_extraction(reporter);
1132}
1133
1134static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
1135    const SkPaint paint;
1136    const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
1137    const SkIRect irect =  { 2, 2, 3, 3 };
1138
1139    // Don't care what these record, as long as they're legal.
1140    canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
1141    canvas->drawBitmapRectToRect(bitmap, &rect, rect, &paint, SkCanvas::kNone_DrawBitmapRectFlag);
1142    canvas->drawBitmapNine(bitmap, irect, rect, &paint);
1143    canvas->drawSprite(bitmap, 1, 1);
1144}
1145
1146static void test_draw_bitmaps(SkCanvas* canvas) {
1147    SkBitmap empty;
1148    draw_bitmaps(empty, canvas);
1149    empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
1150    draw_bitmaps(empty, canvas);
1151}
1152
1153DEF_TEST(Picture_EmptyBitmap, r) {
1154    SkPictureRecorder recorder;
1155    test_draw_bitmaps(recorder.beginRecording(10, 10));
1156    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1157}
1158
1159DEF_TEST(Canvas_EmptyBitmap, r) {
1160    SkBitmap dst;
1161    dst.allocN32Pixels(10, 10);
1162    SkCanvas canvas(dst);
1163
1164    test_draw_bitmaps(&canvas);
1165}
1166
1167DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
1168    // This test is from crbug.com/344987.
1169    // The commands are:
1170    //   saveLayer with paint that modifies alpha
1171    //     drawBitmapRectToRect
1172    //     drawBitmapRectToRect
1173    //   restore
1174    // The bug was that this structure was modified so that:
1175    //  - The saveLayer and restore were eliminated
1176    //  - The alpha was only applied to the first drawBitmapRectToRect
1177
1178    // This test draws blue and red squares inside a 50% transparent
1179    // layer.  Both colours should show up muted.
1180    // When the bug is present, the red square (the second bitmap)
1181    // shows upwith full opacity.
1182
1183    SkBitmap blueBM;
1184    make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
1185    SkBitmap redBM;
1186    make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
1187    SkPaint semiTransparent;
1188    semiTransparent.setAlpha(0x80);
1189
1190    SkPictureRecorder recorder;
1191    SkCanvas* canvas = recorder.beginRecording(100, 100);
1192    canvas->drawARGB(0, 0, 0, 0);
1193
1194    canvas->saveLayer(0, &semiTransparent);
1195    canvas->drawBitmap(blueBM, 25, 25);
1196    canvas->drawBitmap(redBM, 50, 50);
1197    canvas->restore();
1198
1199    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1200
1201    // Now replay the picture back on another canvas
1202    // and check a couple of its pixels.
1203    SkBitmap replayBM;
1204    make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
1205    SkCanvas replayCanvas(replayBM);
1206    picture->playback(&replayCanvas);
1207    replayCanvas.flush();
1208
1209    // With the bug present, at (55, 55) we would get a fully opaque red
1210    // intead of a dark red.
1211    REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
1212    REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
1213}
1214
1215struct CountingBBH : public SkBBoxHierarchy {
1216    mutable int searchCalls;
1217    SkRect rootBound;
1218
1219    CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
1220
1221    void search(const SkRect& query, SkTDArray<unsigned>* results) const override {
1222        this->searchCalls++;
1223    }
1224
1225    void insert(const SkRect[], int) override {}
1226    virtual size_t bytesUsed() const override { return 0; }
1227    SkRect getRootBound() const override { return rootBound; }
1228};
1229
1230class SpoonFedBBHFactory : public SkBBHFactory {
1231public:
1232    explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
1233    SkBBoxHierarchy* operator()(const SkRect&) const override {
1234        return SkRef(fBBH);
1235    }
1236private:
1237    SkBBoxHierarchy* fBBH;
1238};
1239
1240// When the canvas clip covers the full picture, we don't need to call the BBH.
1241DEF_TEST(Picture_SkipBBH, r) {
1242    SkRect bound = SkRect::MakeWH(320, 240);
1243    CountingBBH bbh(bound);
1244    SpoonFedBBHFactory factory(&bbh);
1245
1246    SkPictureRecorder recorder;
1247    SkCanvas* c = recorder.beginRecording(bound, &factory);
1248    // Record a few ops so we don't hit a small- or empty- picture optimization.
1249        c->drawRect(bound, SkPaint());
1250        c->drawRect(bound, SkPaint());
1251    SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
1252
1253    SkCanvas big(640, 480), small(300, 200);
1254
1255    picture->playback(&big);
1256    REPORTER_ASSERT(r, bbh.searchCalls == 0);
1257
1258    picture->playback(&small);
1259    REPORTER_ASSERT(r, bbh.searchCalls == 1);
1260}
1261
1262DEF_TEST(Picture_BitmapLeak, r) {
1263    SkBitmap mut, immut;
1264    mut.allocN32Pixels(300, 200);
1265    immut.allocN32Pixels(300, 200);
1266    immut.setImmutable();
1267    SkASSERT(!mut.isImmutable());
1268    SkASSERT(immut.isImmutable());
1269
1270    // No one can hold a ref on our pixels yet.
1271    REPORTER_ASSERT(r, mut.pixelRef()->unique());
1272    REPORTER_ASSERT(r, immut.pixelRef()->unique());
1273
1274    SkAutoTUnref<const SkPicture> pic;
1275    {
1276        // we want the recorder to go out of scope before our subsequent checks, so we
1277        // place it inside local braces.
1278        SkPictureRecorder rec;
1279        SkCanvas* canvas = rec.beginRecording(1920, 1200);
1280            canvas->drawBitmap(mut, 0, 0);
1281            canvas->drawBitmap(immut, 800, 600);
1282        pic.reset(rec.endRecording());
1283    }
1284
1285    // The picture shares the immutable pixels but copies the mutable ones.
1286    REPORTER_ASSERT(r, mut.pixelRef()->unique());
1287    REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1288
1289    // When the picture goes away, it's just our bitmaps holding the refs.
1290    pic.reset(NULL);
1291    REPORTER_ASSERT(r, mut.pixelRef()->unique());
1292    REPORTER_ASSERT(r, immut.pixelRef()->unique());
1293}
1294
1295// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
1296DEF_TEST(Picture_getRecordingCanvas, r) {
1297    SkPictureRecorder rec;
1298    REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1299    for (int i = 0; i < 3; i++) {
1300        rec.beginRecording(100, 100);
1301        REPORTER_ASSERT(r, rec.getRecordingCanvas());
1302        rec.endRecording()->unref();
1303        REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1304    }
1305}
1306
1307DEF_TEST(MiniRecorderLeftHanging, r) {
1308    // Any shader or other ref-counted effect will do just fine here.
1309    SkPaint paint;
1310    paint.setShader(SkShader::CreateColorShader(SK_ColorRED))->unref();
1311
1312    SkMiniRecorder rec;
1313    REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
1314    // Don't call rec.detachPicture().  Test succeeds by not asserting or leaking the shader.
1315}
1316