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