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