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