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