Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / 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 "SkDecodingImageGenerator.h"
16 #include "SkError.h"
17 #include "SkImageEncoder.h"
18 #include "SkImageGenerator.h"
19 #include "SkPaint.h"
20 #include "SkPicture.h"
21 #include "SkPictureRecorder.h"
22 #include "SkPictureUtils.h"
23 #include "SkPixelRef.h"
24 #include "SkRRect.h"
25 #include "SkRandom.h"
26 #include "SkShader.h"
27 #include "SkStream.h"
28
29 #if SK_SUPPORT_GPU
30 #include "SkSurface.h"
31 #include "GrContextFactory.h"
32 #include "GrPictureUtils.h"
33 #endif
34 #include "Test.h"
35
36 #include "SkLumaColorFilter.h"
37 #include "SkColorFilterImageFilter.h"
38
39 static const int gColorScale = 30;
40 static const int gColorOffset = 60;
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 static void make_checkerboard(SkBitmap* bm, int w, int h, bool immutable) {
51     SkASSERT(w % 2 == 0);
52     SkASSERT(h % 2 == 0);
53     bm->allocPixels(SkImageInfo::Make(w, h, kAlpha_8_SkColorType,
54                                       kPremul_SkAlphaType));
55     SkAutoLockPixels lock(*bm);
56     for (int y = 0; y < h; y += 2) {
57         uint8_t* s = bm->getAddr8(0, y);
58         for (int x = 0; x < w; x += 2) {
59             *s++ = 0xFF;
60             *s++ = 0x00;
61         }
62         s = bm->getAddr8(0, y + 1);
63         for (int x = 0; x < w; x += 2) {
64             *s++ = 0x00;
65             *s++ = 0xFF;
66         }
67     }
68     if (immutable) {
69         bm->setImmutable();
70     }
71 }
72
73 static void init_paint(SkPaint* paint, const SkBitmap &bm) {
74     SkShader* shader = SkShader::CreateBitmapShader(bm,
75                                                     SkShader::kClamp_TileMode,
76                                                     SkShader::kClamp_TileMode);
77     paint->setShader(shader)->unref();
78 }
79
80 typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&,
81                                const SkBitmap&, const SkPoint&,
82                                SkTDArray<SkPixelRef*>* usedPixRefs);
83
84 static void drawpaint_proc(SkCanvas* canvas, const SkBitmap& bm,
85                            const SkBitmap& altBM, const SkPoint& pos,
86                            SkTDArray<SkPixelRef*>* usedPixRefs) {
87     SkPaint paint;
88     init_paint(&paint, bm);
89
90     canvas->drawPaint(paint);
91     *usedPixRefs->append() = bm.pixelRef();
92 }
93
94 static void drawpoints_proc(SkCanvas* canvas, const SkBitmap& bm,
95                             const SkBitmap& altBM, const SkPoint& pos,
96                             SkTDArray<SkPixelRef*>* usedPixRefs) {
97     SkPaint paint;
98     init_paint(&paint, bm);
99
100     // draw a rect
101     SkPoint points[5] = {
102         { pos.fX, pos.fY },
103         { pos.fX + bm.width() - 1, pos.fY },
104         { pos.fX + bm.width() - 1, pos.fY + bm.height() - 1 },
105         { pos.fX, pos.fY + bm.height() - 1 },
106         { pos.fX, pos.fY },
107     };
108
109     canvas->drawPoints(SkCanvas::kPolygon_PointMode, 5, points, paint);
110     *usedPixRefs->append() = bm.pixelRef();
111 }
112
113 static void drawrect_proc(SkCanvas* canvas, const SkBitmap& bm,
114                           const SkBitmap& altBM, const SkPoint& pos,
115                           SkTDArray<SkPixelRef*>* usedPixRefs) {
116     SkPaint paint;
117     init_paint(&paint, bm);
118
119     SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
120     r.offset(pos.fX, pos.fY);
121
122     canvas->drawRect(r, paint);
123     *usedPixRefs->append() = bm.pixelRef();
124 }
125
126 static void drawoval_proc(SkCanvas* canvas, const SkBitmap& bm,
127                           const SkBitmap& altBM, const SkPoint& pos,
128                           SkTDArray<SkPixelRef*>* usedPixRefs) {
129     SkPaint paint;
130     init_paint(&paint, bm);
131
132     SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
133     r.offset(pos.fX, pos.fY);
134
135     canvas->drawOval(r, paint);
136     *usedPixRefs->append() = bm.pixelRef();
137 }
138
139 static void drawrrect_proc(SkCanvas* canvas, const SkBitmap& bm,
140                            const SkBitmap& altBM, const SkPoint& pos,
141                            SkTDArray<SkPixelRef*>* usedPixRefs) {
142     SkPaint paint;
143     init_paint(&paint, bm);
144
145     SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
146     r.offset(pos.fX, pos.fY);
147
148     SkRRect rr;
149     rr.setRectXY(r, SkIntToScalar(bm.width())/4, SkIntToScalar(bm.height())/4);
150     canvas->drawRRect(rr, paint);
151     *usedPixRefs->append() = bm.pixelRef();
152 }
153
154 static void drawpath_proc(SkCanvas* canvas, const SkBitmap& bm,
155                           const SkBitmap& altBM, const SkPoint& pos,
156                           SkTDArray<SkPixelRef*>* usedPixRefs) {
157     SkPaint paint;
158     init_paint(&paint, bm);
159
160     SkPath path;
161     path.lineTo(bm.width()/2.0f, SkIntToScalar(bm.height()));
162     path.lineTo(SkIntToScalar(bm.width()), 0);
163     path.close();
164     path.offset(pos.fX, pos.fY);
165
166     canvas->drawPath(path, paint);
167     *usedPixRefs->append() = bm.pixelRef();
168 }
169
170 static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm,
171                             const SkBitmap& altBM, const SkPoint& pos,
172                             SkTDArray<SkPixelRef*>* usedPixRefs) {
173     canvas->drawBitmap(bm, pos.fX, pos.fY, NULL);
174     *usedPixRefs->append() = bm.pixelRef();
175 }
176
177 static void drawbitmap_withshader_proc(SkCanvas* canvas, const SkBitmap& bm,
178                                        const SkBitmap& altBM, const SkPoint& pos,
179                                        SkTDArray<SkPixelRef*>* usedPixRefs) {
180     SkPaint paint;
181     init_paint(&paint, bm);
182
183     // The bitmap in the paint is ignored unless we're drawing an A8 bitmap
184     canvas->drawBitmap(altBM, pos.fX, pos.fY, &paint);
185     *usedPixRefs->append() = bm.pixelRef();
186     *usedPixRefs->append() = altBM.pixelRef();
187 }
188
189 static void drawsprite_proc(SkCanvas* canvas, const SkBitmap& bm,
190                             const SkBitmap& altBM, const SkPoint& pos,
191                             SkTDArray<SkPixelRef*>* usedPixRefs) {
192     const SkMatrix& ctm = canvas->getTotalMatrix();
193
194     SkPoint p(pos);
195     ctm.mapPoints(&p, 1);
196
197     canvas->drawSprite(bm, (int)p.fX, (int)p.fY, NULL);
198     *usedPixRefs->append() = bm.pixelRef();
199 }
200
201 #if 0
202 // Although specifiable, this case doesn't seem to make sense (i.e., the
203 // bitmap in the shader is never used).
204 static void drawsprite_withshader_proc(SkCanvas* canvas, const SkBitmap& bm,
205                                        const SkBitmap& altBM, const SkPoint& pos,
206                                        SkTDArray<SkPixelRef*>* usedPixRefs) {
207     SkPaint paint;
208     init_paint(&paint, bm);
209
210     const SkMatrix& ctm = canvas->getTotalMatrix();
211
212     SkPoint p(pos);
213     ctm.mapPoints(&p, 1);
214
215     canvas->drawSprite(altBM, (int)p.fX, (int)p.fY, &paint);
216     *usedPixRefs->append() = bm.pixelRef();
217     *usedPixRefs->append() = altBM.pixelRef();
218 }
219 #endif
220
221 static void drawbitmaprect_proc(SkCanvas* canvas, const SkBitmap& bm,
222                                 const SkBitmap& altBM, const SkPoint& pos,
223                                 SkTDArray<SkPixelRef*>* usedPixRefs) {
224     SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
225
226     r.offset(pos.fX, pos.fY);
227     canvas->drawBitmapRectToRect(bm, NULL, r, NULL);
228     *usedPixRefs->append() = bm.pixelRef();
229 }
230
231 static void drawbitmaprect_withshader_proc(SkCanvas* canvas,
232                                            const SkBitmap& bm,
233                                            const SkBitmap& altBM,
234                                            const SkPoint& pos,
235                                            SkTDArray<SkPixelRef*>* usedPixRefs) {
236     SkPaint paint;
237     init_paint(&paint, bm);
238
239     SkRect r = { 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) };
240     r.offset(pos.fX, pos.fY);
241
242     // The bitmap in the paint is ignored unless we're drawing an A8 bitmap
243     canvas->drawBitmapRectToRect(altBM, NULL, r, &paint);
244     *usedPixRefs->append() = bm.pixelRef();
245     *usedPixRefs->append() = altBM.pixelRef();
246 }
247
248 static void drawtext_proc(SkCanvas* canvas, const SkBitmap& bm,
249                           const SkBitmap& altBM, const SkPoint& pos,
250                           SkTDArray<SkPixelRef*>* usedPixRefs) {
251     SkPaint paint;
252     init_paint(&paint, bm);
253     paint.setTextSize(SkIntToScalar(1.5*bm.width()));
254
255     canvas->drawText("0", 1, pos.fX, pos.fY+bm.width(), paint);
256     *usedPixRefs->append() = bm.pixelRef();
257 }
258
259 static void drawpostext_proc(SkCanvas* canvas, const SkBitmap& bm,
260                              const SkBitmap& altBM, const SkPoint& pos,
261                              SkTDArray<SkPixelRef*>* usedPixRefs) {
262     SkPaint paint;
263     init_paint(&paint, bm);
264     paint.setTextSize(SkIntToScalar(1.5*bm.width()));
265
266     SkPoint point = { pos.fX, pos.fY + bm.height() };
267     canvas->drawPosText("O", 1, &point, paint);
268     *usedPixRefs->append() = bm.pixelRef();
269 }
270
271 static void drawtextonpath_proc(SkCanvas* canvas, const SkBitmap& bm,
272                                 const SkBitmap& altBM, const SkPoint& pos,
273                                 SkTDArray<SkPixelRef*>* usedPixRefs) {
274     SkPaint paint;
275
276     init_paint(&paint, bm);
277     paint.setTextSize(SkIntToScalar(1.5*bm.width()));
278
279     SkPath path;
280     path.lineTo(SkIntToScalar(bm.width()), 0);
281     path.offset(pos.fX, pos.fY+bm.height());
282
283     canvas->drawTextOnPath("O", 1, path, NULL, paint);
284     *usedPixRefs->append() = bm.pixelRef();
285 }
286
287 static void drawverts_proc(SkCanvas* canvas, const SkBitmap& bm,
288                            const SkBitmap& altBM, const SkPoint& pos,
289                            SkTDArray<SkPixelRef*>* usedPixRefs) {
290     SkPaint paint;
291     init_paint(&paint, bm);
292
293     SkPoint verts[4] = {
294         { pos.fX, pos.fY },
295         { pos.fX + bm.width(), pos.fY },
296         { pos.fX + bm.width(), pos.fY + bm.height() },
297         { pos.fX, pos.fY + bm.height() }
298     };
299     SkPoint texs[4] = { { 0, 0 },
300                         { SkIntToScalar(bm.width()), 0 },
301                         { SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) },
302                         { 0, SkIntToScalar(bm.height()) } };
303     uint16_t indices[6] = { 0, 1, 2, 0, 2, 3 };
304
305     canvas->drawVertices(SkCanvas::kTriangles_VertexMode, 4, verts, texs, NULL, NULL,
306                          indices, 6, paint);
307     *usedPixRefs->append() = bm.pixelRef();
308 }
309
310 // Return a picture with the bitmaps drawn at the specified positions.
311 static SkPicture* record_bitmaps(const SkBitmap bm[],
312                                  const SkPoint pos[],
313                                  SkTDArray<SkPixelRef*> analytic[],
314                                  int count,
315                                  DrawBitmapProc proc) {
316     SkPictureRecorder recorder;
317     SkCanvas* canvas = recorder.beginRecording(1000, 1000);
318     for (int i = 0; i < count; ++i) {
319         analytic[i].rewind();
320         canvas->save();
321         SkRect clipRect = SkRect::MakeXYWH(pos[i].fX, pos[i].fY,
322                                            SkIntToScalar(bm[i].width()),
323                                            SkIntToScalar(bm[i].height()));
324         canvas->clipRect(clipRect, SkRegion::kIntersect_Op);
325         proc(canvas, bm[i], bm[count+i], pos[i], &analytic[i]);
326         canvas->restore();
327     }
328     return recorder.endRecording();
329 }
330
331 static void rand_rect(SkRect* rect, SkRandom& rand, SkScalar W, SkScalar H) {
332     rect->fLeft   = rand.nextRangeScalar(-W, 2*W);
333     rect->fTop    = rand.nextRangeScalar(-H, 2*H);
334     rect->fRight  = rect->fLeft + rand.nextRangeScalar(0, W);
335     rect->fBottom = rect->fTop + rand.nextRangeScalar(0, H);
336
337     // we integralize rect to make our tests more predictable, since Gather is
338     // a little sloppy.
339     SkIRect ir;
340     rect->round(&ir);
341     rect->set(ir);
342 }
343
344 static void draw(SkPicture* pic, int width, int height, SkBitmap* result) {
345     make_bm(result, width, height, SK_ColorBLACK, false);
346
347     SkCanvas canvas(*result);
348     canvas.drawPicture(pic);
349 }
350
351 template <typename T> int find_index(const T* array, T elem, int count) {
352     for (int i = 0; i < count; ++i) {
353         if (array[i] == elem) {
354             return i;
355         }
356     }
357     return -1;
358 }
359
360 // Return true if 'ref' is found in array[]
361 static bool find(SkPixelRef const * const * array, SkPixelRef const * ref, int count) {
362     return find_index<const SkPixelRef*>(array, ref, count) >= 0;
363 }
364
365 // Look at each pixel that is inside 'subset', and if its color appears in
366 // colors[], find the corresponding value in refs[] and append that ref into
367 // array, skipping duplicates of the same value.
368 // Note that gathering pixelRefs from rendered colors suffers from the problem
369 // that multiple simultaneous textures (e.g., A8 for alpha and 8888 for color)
370 // isn't easy to reconstruct.
371 static void gather_from_image(const SkBitmap& bm, SkPixelRef* const refs[],
372                               int count, SkTDArray<SkPixelRef*>* array,
373                               const SkRect& subset) {
374     SkIRect ir;
375     subset.roundOut(&ir);
376
377     if (!ir.intersect(0, 0, bm.width()-1, bm.height()-1)) {
378         return;
379     }
380
381     // Since we only want to return unique values in array, when we scan we just
382     // set a bit for each index'd color found. In practice we only have a few
383     // distinct colors, so we just use an int's bits as our array. Hence the
384     // assert that count <= number-of-bits-in-our-int.
385     SkASSERT((unsigned)count <= 32);
386     uint32_t bitarray = 0;
387
388     SkAutoLockPixels alp(bm);
389
390     for (int y = ir.fTop; y < ir.fBottom; ++y) {
391         for (int x = ir.fLeft; x < ir.fRight; ++x) {
392             SkPMColor pmc = *bm.getAddr32(x, y);
393             // the only good case where the color is not found would be if
394             // the color is transparent, meaning no bitmap was drawn in that
395             // pixel.
396             if (pmc) {
397                 uint32_t index = SkGetPackedR32(pmc);
398                 SkASSERT(SkGetPackedG32(pmc) == index);
399                 SkASSERT(SkGetPackedB32(pmc) == index);
400                 if (0 == index) {
401                     continue;           // background color
402                 }
403                 SkASSERT(0 == (index - gColorOffset) % gColorScale);
404                 index = (index - gColorOffset) / gColorScale;
405                 SkASSERT(static_cast<int>(index) < count);
406                 bitarray |= 1 << index;
407             }
408         }
409     }
410
411     for (int i = 0; i < count; ++i) {
412         if (bitarray & (1 << i)) {
413             *array->append() = refs[i];
414         }
415     }
416 }
417
418 static void gather_from_analytic(const SkPoint pos[], SkScalar w, SkScalar h,
419                                  const SkTDArray<SkPixelRef*> analytic[],
420                                  int count,
421                                  SkTDArray<SkPixelRef*>* result,
422                                  const SkRect& subset) {
423     for (int i = 0; i < count; ++i) {
424         SkRect rect = SkRect::MakeXYWH(pos[i].fX, pos[i].fY, w, h);
425
426         if (SkRect::Intersects(subset, rect)) {
427             result->append(analytic[i].count(), analytic[i].begin());
428         }
429     }
430 }
431
432
433 static const struct {
434     const DrawBitmapProc proc;
435     const char* const desc;
436 } gProcs[] = {
437     {drawpaint_proc, "drawpaint"},
438     {drawpoints_proc, "drawpoints"},
439     {drawrect_proc, "drawrect"},
440     {drawoval_proc, "drawoval"},
441     {drawrrect_proc, "drawrrect"},
442     {drawpath_proc, "drawpath"},
443     {drawbitmap_proc, "drawbitmap"},
444     {drawbitmap_withshader_proc, "drawbitmap_withshader"},
445     {drawsprite_proc, "drawsprite"},
446 #if 0
447     {drawsprite_withshader_proc, "drawsprite_withshader"},
448 #endif
449     {drawbitmaprect_proc, "drawbitmaprect"},
450     {drawbitmaprect_withshader_proc, "drawbitmaprect_withshader"},
451     {drawtext_proc, "drawtext"},
452     {drawpostext_proc, "drawpostext"},
453     {drawtextonpath_proc, "drawtextonpath"},
454     {drawverts_proc, "drawverts"},
455 };
456
457 static void create_textures(SkBitmap* bm, SkPixelRef** refs, int num, int w, int h) {
458     // Our convention is that the color components contain an encoding of
459     // the index of their corresponding bitmap/pixelref. (0,0,0,0) is
460     // reserved for the background
461     for (int i = 0; i < num; ++i) {
462         make_bm(&bm[i], w, h,
463                 SkColorSetARGB(0xFF,
464                                gColorScale*i+gColorOffset,
465                                gColorScale*i+gColorOffset,
466                                gColorScale*i+gColorOffset),
467                 true);
468         refs[i] = bm[i].pixelRef();
469     }
470
471     // The A8 alternate bitmaps are all BW checkerboards
472     for (int i = 0; i < num; ++i) {
473         make_checkerboard(&bm[num+i], w, h, true);
474         refs[num+i] = bm[num+i].pixelRef();
475     }
476 }
477
478 static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
479     const int IW = 32;
480     const int IH = IW;
481     const SkScalar W = SkIntToScalar(IW);
482     const SkScalar H = W;
483
484     static const int N = 4;
485     SkBitmap bm[2*N];
486     SkPixelRef* refs[2*N];
487     SkTDArray<SkPixelRef*> analytic[N];
488
489     const SkPoint pos[N] = {
490         { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
491     };
492
493     create_textures(bm, refs, N, IW, IH);
494
495     SkRandom rand;
496     for (size_t k = 0; k < SK_ARRAY_COUNT(gProcs); ++k) {
497         SkAutoTUnref<SkPicture> pic(
498             record_bitmaps(bm, pos, analytic, N, gProcs[k].proc));
499
500         REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0);
501         // quick check for a small piece of each quadrant, which should just
502         // contain 1 or 2 bitmaps.
503         for (size_t  i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
504             SkRect r;
505             r.set(2, 2, W - 2, H - 2);
506             r.offset(pos[i].fX, pos[i].fY);
507             SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r));
508             if (!data) {
509                 ERRORF(reporter, "SkPictureUtils::GatherPixelRefs returned "
510                        "NULL for %s.", gProcs[k].desc);
511                 continue;
512             }
513             SkPixelRef** gatheredRefs = (SkPixelRef**)data->data();
514             int count = static_cast<int>(data->size() / sizeof(SkPixelRef*));
515             REPORTER_ASSERT(reporter, 1 == count || 2 == count);
516             if (1 == count) {
517                 REPORTER_ASSERT(reporter, gatheredRefs[0] == refs[i]);
518             } else if (2 == count) {
519                 REPORTER_ASSERT(reporter,
520                     (gatheredRefs[0] == refs[i] && gatheredRefs[1] == refs[i+N]) ||
521                     (gatheredRefs[1] == refs[i] && gatheredRefs[0] == refs[i+N]));
522             }
523         }
524
525         SkBitmap image;
526         draw(pic, 2*IW, 2*IH, &image);
527
528         // Test a bunch of random (mostly) rects, and compare the gather results
529         // with a deduced list of refs by looking at the colors drawn.
530         for (int j = 0; j < 100; ++j) {
531             SkRect r;
532             rand_rect(&r, rand, 2*W, 2*H);
533
534             SkTDArray<SkPixelRef*> fromImage;
535             gather_from_image(image, refs, N, &fromImage, r);
536
537             SkTDArray<SkPixelRef*> fromAnalytic;
538             gather_from_analytic(pos, W, H, analytic, N, &fromAnalytic, r);
539
540             SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
541             size_t dataSize = data ? data->size() : 0;
542             int gatherCount = static_cast<int>(dataSize / sizeof(SkPixelRef*));
543             SkASSERT(gatherCount * sizeof(SkPixelRef*) == dataSize);
544             SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL;
545             SkAutoDataUnref adu(data);
546
547             // Everything that we saw drawn should appear in the analytic list
548             // but the analytic list may contain some pixelRefs that were not
549             // seen in the image (e.g., A8 textures used as masks)
550             for (int i = 0; i < fromImage.count(); ++i) {
551                 if (-1 == fromAnalytic.find(fromImage[i])) {
552                     ERRORF(reporter, "PixelRef missing %d %s",
553                            i, gProcs[k].desc);
554                 }
555             }
556
557             /*
558              *  GatherPixelRefs is conservative, so it can return more bitmaps
559              *  than are strictly required. Thus our check here is only that
560              *  Gather didn't miss any that we actually needed. Even that isn't
561              *  a strict requirement on Gather, which is meant to be quick and
562              *  only mostly-correct, but at the moment this test should work.
563              */
564             for (int i = 0; i < fromAnalytic.count(); ++i) {
565                 bool found = find(gatherRefs, fromAnalytic[i], gatherCount);
566                 if (!found) {
567                     ERRORF(reporter, "PixelRef missing %d %s",
568                            i, gProcs[k].desc);
569                 }
570 #if 0
571                 // enable this block of code to debug failures, as it will rerun
572                 // the case that failed.
573                 if (!found) {
574                     SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
575                     size_t dataSize = data ? data->size() : 0;
576                 }
577 #endif
578             }
579         }
580     }
581 }
582
583 /* Hit a few SkPicture::Analysis cases not handled elsewhere. */
584 static void test_analysis(skiatest::Reporter* reporter) {
585     SkPictureRecorder recorder;
586
587     SkCanvas* canvas = recorder.beginRecording(100, 100);
588     {
589         canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ());
590     }
591     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
592     REPORTER_ASSERT(reporter, !picture->willPlayBackBitmaps());
593
594     canvas = recorder.beginRecording(100, 100);
595     {
596         SkPaint paint;
597         // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader
598         // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here.
599         SkBitmap bitmap;
600         bitmap.allocPixels(SkImageInfo::MakeN32Premul(2, 2));
601         bitmap.eraseColor(SK_ColorBLUE);
602         *(bitmap.getAddr32(0, 0)) = SK_ColorGREEN;
603         SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode,
604                                                         SkShader::kClamp_TileMode);
605         paint.setShader(shader)->unref();
606         REPORTER_ASSERT(reporter,
607                         shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType);
608
609         canvas->drawRect(SkRect::MakeWH(10, 10), paint);
610     }
611     picture.reset(recorder.endRecording());
612     REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps());
613 }
614
615
616 static void test_gatherpixelrefsandrects(skiatest::Reporter* reporter) {
617     const int IW = 32;
618     const int IH = IW;
619     const SkScalar W = SkIntToScalar(IW);
620     const SkScalar H = W;
621
622     static const int N = 4;
623     SkBitmap bm[2*N];
624     SkPixelRef* refs[2*N];
625     SkTDArray<SkPixelRef*> analytic[N];
626
627     const SkPoint pos[N] = {
628         { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
629     };
630
631     create_textures(bm, refs, N, IW, IH);
632
633     SkRandom rand;
634     for (size_t k = 0; k < SK_ARRAY_COUNT(gProcs); ++k) {
635         SkAutoTUnref<SkPicture> pic(
636             record_bitmaps(bm, pos, analytic, N, gProcs[k].proc));
637
638         REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0);
639
640         SkAutoTUnref<SkPictureUtils::SkPixelRefContainer> prCont(
641                                 new SkPictureUtils::SkPixelRefsAndRectsList);
642
643         SkPictureUtils::GatherPixelRefsAndRects(pic, prCont);
644
645         // quick check for a small piece of each quadrant, which should just
646         // contain 1 or 2 bitmaps.
647         for (size_t  i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
648             SkRect r;
649             r.set(2, 2, W - 2, H - 2);
650             r.offset(pos[i].fX, pos[i].fY);
651
652             SkTDArray<SkPixelRef*> gatheredRefs;
653             prCont->query(r, &gatheredRefs);
654
655             int count = gatheredRefs.count();
656             REPORTER_ASSERT(reporter, 1 == count || 2 == count);
657             if (1 == count) {
658                 REPORTER_ASSERT(reporter, gatheredRefs[0] == refs[i]);
659             } else if (2 == count) {
660                 REPORTER_ASSERT(reporter,
661                     (gatheredRefs[0] == refs[i] && gatheredRefs[1] == refs[i+N]) ||
662                     (gatheredRefs[1] == refs[i] && gatheredRefs[0] == refs[i+N]));
663             }
664         }
665
666         SkBitmap image;
667         draw(pic, 2*IW, 2*IH, &image);
668
669         // Test a bunch of random (mostly) rects, and compare the gather results
670         // with the analytic results and the pixel refs seen in a rendering.
671         for (int j = 0; j < 100; ++j) {
672             SkRect r;
673             rand_rect(&r, rand, 2*W, 2*H);
674
675             SkTDArray<SkPixelRef*> fromImage;
676             gather_from_image(image, refs, N, &fromImage, r);
677
678             SkTDArray<SkPixelRef*> fromAnalytic;
679             gather_from_analytic(pos, W, H, analytic, N, &fromAnalytic, r);
680
681             SkTDArray<SkPixelRef*> gatheredRefs;
682             prCont->query(r, &gatheredRefs);
683
684             // Everything that we saw drawn should appear in the analytic list
685             // but the analytic list may contain some pixelRefs that were not
686             // seen in the image (e.g., A8 textures used as masks)
687             for (int i = 0; i < fromImage.count(); ++i) {
688                 REPORTER_ASSERT(reporter, -1 != fromAnalytic.find(fromImage[i]));
689             }
690
691             // Everything in the analytic list should appear in the gathered
692             // list.
693             for (int i = 0; i < fromAnalytic.count(); ++i) {
694                 REPORTER_ASSERT(reporter, -1 != gatheredRefs.find(fromAnalytic[i]));
695             }
696         }
697     }
698 }
699
700 #ifdef SK_DEBUG
701 // Ensure that deleting an empty SkPicture does not assert. Asserts only fire
702 // in debug mode, so only run in debug mode.
703 static void test_deleting_empty_picture() {
704     SkPictureRecorder recorder;
705     // Creates an SkPictureRecord
706     recorder.beginRecording(0, 0);
707     // Turns that into an SkPicture
708     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
709     // Ceates a new SkPictureRecord
710     recorder.beginRecording(0, 0);
711 }
712
713 // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
714 static void test_serializing_empty_picture() {
715     SkPictureRecorder recorder;
716     recorder.beginRecording(0, 0);
717     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
718     SkDynamicMemoryWStream stream;
719     picture->serialize(&stream);
720 }
721 #endif
722
723 static void rand_op(SkCanvas* canvas, SkRandom& rand) {
724     SkPaint paint;
725     SkRect rect = SkRect::MakeWH(50, 50);
726
727     SkScalar unit = rand.nextUScalar1();
728     if (unit <= 0.3) {
729 //        SkDebugf("save\n");
730         canvas->save();
731     } else if (unit <= 0.6) {
732 //        SkDebugf("restore\n");
733         canvas->restore();
734     } else if (unit <= 0.9) {
735 //        SkDebugf("clip\n");
736         canvas->clipRect(rect);
737     } else {
738 //        SkDebugf("draw\n");
739         canvas->drawPaint(paint);
740     }
741 }
742
743 #if SK_SUPPORT_GPU
744
745 static void test_gpu_veto(skiatest::Reporter* reporter) {
746     SkPictureRecorder recorder;
747
748     SkCanvas* canvas = recorder.beginRecording(100, 100);
749     {
750         SkPath path;
751         path.moveTo(0, 0);
752         path.lineTo(50, 50);
753
754         SkScalar intervals[] = { 1.0f, 1.0f };
755         SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0));
756
757         SkPaint paint;
758         paint.setStyle(SkPaint::kStroke_Style);
759         paint.setPathEffect(dash);
760
761         canvas->drawPath(path, paint);
762     }
763     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
764     // path effects currently render an SkPicture undesireable for GPU rendering
765
766     const char *reason = NULL;
767     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL, &reason));
768     REPORTER_ASSERT(reporter, reason);
769
770     canvas = recorder.beginRecording(100, 100);
771     {
772         SkPath path;
773
774         path.moveTo(0, 0);
775         path.lineTo(0, 50);
776         path.lineTo(25, 25);
777         path.lineTo(50, 50);
778         path.lineTo(50, 0);
779         path.close();
780         REPORTER_ASSERT(reporter, !path.isConvex());
781
782         SkPaint paint;
783         paint.setAntiAlias(true);
784         for (int i = 0; i < 50; ++i) {
785             canvas->drawPath(path, paint);
786         }
787     }
788     picture.reset(recorder.endRecording());
789     // A lot of small AA concave paths should be fine for GPU rendering
790     REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(NULL));
791
792     canvas = recorder.beginRecording(100, 100);
793     {
794         SkPath path;
795
796         path.moveTo(0, 0);
797         path.lineTo(0, 100);
798         path.lineTo(50, 50);
799         path.lineTo(100, 100);
800         path.lineTo(100, 0);
801         path.close();
802         REPORTER_ASSERT(reporter, !path.isConvex());
803
804         SkPaint paint;
805         paint.setAntiAlias(true);
806         for (int i = 0; i < 50; ++i) {
807             canvas->drawPath(path, paint);
808         }
809     }
810     picture.reset(recorder.endRecording());
811     // A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering
812     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
813
814     canvas = recorder.beginRecording(100, 100);
815     {
816         SkPath path;
817
818         path.moveTo(0, 0);
819         path.lineTo(0, 50);
820         path.lineTo(25, 25);
821         path.lineTo(50, 50);
822         path.lineTo(50, 0);
823         path.close();
824         REPORTER_ASSERT(reporter, !path.isConvex());
825
826         SkPaint paint;
827         paint.setAntiAlias(true);
828         paint.setStyle(SkPaint::kStroke_Style);
829         paint.setStrokeWidth(0);
830         for (int i = 0; i < 50; ++i) {
831             canvas->drawPath(path, paint);
832         }
833     }
834     picture.reset(recorder.endRecording());
835     // hairline stroked AA concave paths are fine for GPU rendering
836     REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(NULL));
837
838     canvas = recorder.beginRecording(100, 100);
839     {
840         SkPaint paint;
841         SkScalar intervals [] = { 10, 20 };
842         SkPathEffect* pe = SkDashPathEffect::Create(intervals, 2, 25);
843         paint.setPathEffect(pe)->unref();
844
845         SkPoint points [2] = { { 0, 0 }, { 100, 0 } };
846         canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint);
847     }
848     picture.reset(recorder.endRecording());
849     // fast-path dashed effects are fine for GPU rendering ...
850     REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(NULL));
851
852     canvas = recorder.beginRecording(100, 100);
853     {
854         SkPaint paint;
855         SkScalar intervals [] = { 10, 20 };
856         SkPathEffect* pe = SkDashPathEffect::Create(intervals, 2, 25);
857         paint.setPathEffect(pe)->unref();
858
859         canvas->drawRect(SkRect::MakeWH(10, 10), paint);
860     }
861     picture.reset(recorder.endRecording());
862     // ... but only when applied to drawPoint() calls
863     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
864
865     // Nest the previous picture inside a new one.
866     canvas = recorder.beginRecording(100, 100);
867     {
868         canvas->drawPicture(picture.get());
869     }
870     picture.reset(recorder.endRecording());
871     REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
872 }
873
874 static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
875                                           GrContextFactory* factory) {
876     for (int i= 0; i < GrContextFactory::kGLContextTypeCnt; ++i) {
877         GrContextFactory::GLContextType glCtxType = (GrContextFactory::GLContextType) i;
878
879         if (!GrContextFactory::IsRenderingGLContext(glCtxType)) {
880             continue;
881         }
882
883         GrContext* context = factory->get(glCtxType);
884
885         if (NULL == context) {
886             continue;
887         }
888
889         static const int kWidth = 100;
890         static const int kHeight = 100;
891
892         // Create complex paint that the bounding box computation code can't
893         // optimize away
894         SkScalar blueToRedMatrix[20] = { 0 };
895         blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
896         SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
897         SkAutoTUnref<SkImageFilter> filter(SkColorFilterImageFilter::Create(blueToRed.get()));
898
899         SkPaint complexPaint;
900         complexPaint.setImageFilter(filter);
901
902         SkAutoTUnref<SkPicture> pict, child;
903
904         {
905             SkPictureRecorder recorder;
906
907             SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight));
908
909             c->saveLayer(NULL, &complexPaint);
910             c->restore();
911
912             child.reset(recorder.endRecording());
913         }
914
915         // create a picture with the structure:
916         // 1)
917         //      SaveLayer
918         //      Restore
919         // 2)
920         //      SaveLayer
921         //          Translate
922         //          SaveLayer w/ bound
923         //          Restore
924         //      Restore
925         // 3)
926         //      SaveLayer w/ copyable paint
927         //      Restore
928         // 4)
929         //      SaveLayer
930         //          DrawPicture (which has a SaveLayer/Restore pair)
931         //      Restore
932         // 5)
933         //      SaveLayer
934         //          DrawPicture with Matrix & Paint (with SaveLayer/Restore pair)
935         //      Restore
936         {
937             SkPictureRecorder recorder;
938
939             SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth),
940                                                   SkIntToScalar(kHeight));
941             // 1)
942             c->saveLayer(NULL, &complexPaint); // layer #0
943             c->restore();
944
945             // 2)
946             c->saveLayer(NULL, NULL); // layer #1
947                 c->translate(kWidth/2.0f, kHeight/2.0f);
948                 SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
949                 c->saveLayer(&r, &complexPaint); // layer #2
950                 c->restore();
951             c->restore();
952
953             // 3)
954             {
955                 c->saveLayer(NULL, &complexPaint); // layer #3
956                 c->restore();
957             }
958
959             SkPaint layerPaint;
960             layerPaint.setColor(SK_ColorRED);  // Non-alpha only to avoid SaveLayerDrawRestoreNooper
961             // 4)
962             {
963                 c->saveLayer(NULL, &layerPaint);  // layer #4
964                     c->drawPicture(child);  // layer #5 inside picture
965                 c->restore();
966             }
967             // 5
968             {
969                 SkPaint picturePaint;
970                 SkMatrix trans;
971                 trans.setTranslate(10, 10);
972
973                 c->saveLayer(NULL, &layerPaint);  // layer #6
974                     c->drawPicture(child, &trans, &picturePaint); // layer #7 inside picture
975                 c->restore();
976             }
977
978             pict.reset(recorder.endRecording());
979         }
980
981         // Now test out the SaveLayer extraction
982         {
983             SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
984
985             SkAutoTUnref<SkSurface> surface(SkSurface::NewScratchRenderTarget(context, info));
986
987             SkCanvas* canvas = surface->getCanvas();
988
989             canvas->EXPERIMENTAL_optimize(pict);
990
991             SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
992
993             const SkPicture::AccelData* data = pict->EXPERIMENTAL_getAccelData(key);
994             REPORTER_ASSERT(reporter, data);
995
996             const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
997             REPORTER_ASSERT(reporter, 8 == gpuData->numSaveLayers());
998
999             const GrAccelData::SaveLayerInfo& info0 = gpuData->saveLayerInfo(0);
1000             // The parent/child layers appear in reverse order
1001             const GrAccelData::SaveLayerInfo& info1 = gpuData->saveLayerInfo(2);
1002             const GrAccelData::SaveLayerInfo& info2 = gpuData->saveLayerInfo(1);
1003
1004             const GrAccelData::SaveLayerInfo& info3 = gpuData->saveLayerInfo(3);
1005
1006             // The parent/child layers appear in reverse order
1007             const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(5);
1008             const GrAccelData::SaveLayerInfo& info5 = gpuData->saveLayerInfo(4);
1009
1010             // The parent/child layers appear in reverse order
1011             const GrAccelData::SaveLayerInfo& info6 = gpuData->saveLayerInfo(7);
1012             const GrAccelData::SaveLayerInfo& info7 = gpuData->saveLayerInfo(6);
1013
1014             REPORTER_ASSERT(reporter, NULL == info0.fPicture);
1015             REPORTER_ASSERT(reporter, kWidth == info0.fBounds.width() &&
1016                                       kHeight == info0.fBounds.height());
1017             REPORTER_ASSERT(reporter, info0.fLocalMat.isIdentity());
1018             REPORTER_ASSERT(reporter, info0.fPreMat.isIdentity());
1019             REPORTER_ASSERT(reporter, 0 == info0.fBounds.fLeft && 0 == info0.fBounds.fTop);
1020             REPORTER_ASSERT(reporter, NULL != info0.fPaint);
1021             REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
1022
1023             REPORTER_ASSERT(reporter, NULL == info1.fPicture);
1024             REPORTER_ASSERT(reporter, kWidth == info1.fBounds.width() &&
1025                                       kHeight == info1.fBounds.height());
1026             REPORTER_ASSERT(reporter, info1.fLocalMat.isIdentity());
1027             REPORTER_ASSERT(reporter, info1.fPreMat.isIdentity());
1028             REPORTER_ASSERT(reporter, 0 == info1.fBounds.fLeft && 0 == info1.fBounds.fTop);
1029             REPORTER_ASSERT(reporter, NULL == info1.fPaint);
1030             REPORTER_ASSERT(reporter, !info1.fIsNested &&
1031                                       info1.fHasNestedLayers); // has a nested SL
1032
1033             REPORTER_ASSERT(reporter, NULL == info2.fPicture);
1034             REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.width() &&
1035                                       kHeight / 2 == info2.fBounds.height()); // bound reduces size
1036             REPORTER_ASSERT(reporter, !info2.fLocalMat.isIdentity());
1037             REPORTER_ASSERT(reporter, info2.fPreMat.isIdentity());
1038             REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.fLeft &&   // translated
1039                                       kHeight / 2 == info2.fBounds.fTop);
1040             REPORTER_ASSERT(reporter, NULL != info2.fPaint);
1041             REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
1042
1043             REPORTER_ASSERT(reporter, NULL == info3.fPicture);
1044             REPORTER_ASSERT(reporter, kWidth == info3.fBounds.width() &&
1045                                       kHeight == info3.fBounds.height());
1046             REPORTER_ASSERT(reporter, info3.fLocalMat.isIdentity());
1047             REPORTER_ASSERT(reporter, info3.fPreMat.isIdentity());
1048             REPORTER_ASSERT(reporter, 0 == info3.fBounds.fLeft && 0 == info3.fBounds.fTop);
1049             REPORTER_ASSERT(reporter, info3.fPaint);
1050             REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
1051
1052             REPORTER_ASSERT(reporter, NULL == info4.fPicture);
1053             REPORTER_ASSERT(reporter, kWidth == info4.fBounds.width() &&
1054                                       kHeight == info4.fBounds.height());
1055             REPORTER_ASSERT(reporter, 0 == info4.fBounds.fLeft && 0 == info4.fBounds.fTop);
1056             REPORTER_ASSERT(reporter, info4.fLocalMat.isIdentity());
1057             REPORTER_ASSERT(reporter, info4.fPreMat.isIdentity());
1058             REPORTER_ASSERT(reporter, info4.fPaint);
1059             REPORTER_ASSERT(reporter, !info4.fIsNested &&
1060                                       info4.fHasNestedLayers); // has a nested SL
1061
1062             REPORTER_ASSERT(reporter, child == info5.fPicture); // in a child picture
1063             REPORTER_ASSERT(reporter, kWidth == info5.fBounds.width() &&
1064                                       kHeight == info5.fBounds.height());
1065             REPORTER_ASSERT(reporter, 0 == info5.fBounds.fLeft && 0 == info5.fBounds.fTop);
1066             REPORTER_ASSERT(reporter, info5.fLocalMat.isIdentity());
1067             REPORTER_ASSERT(reporter, info5.fPreMat.isIdentity());
1068             REPORTER_ASSERT(reporter, NULL != info5.fPaint);
1069             REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested
1070
1071             REPORTER_ASSERT(reporter, NULL == info6.fPicture);
1072             REPORTER_ASSERT(reporter, kWidth-10 == info6.fBounds.width() &&
1073                                       kHeight-10 == info6.fBounds.height());
1074             REPORTER_ASSERT(reporter, 10 == info6.fBounds.fLeft && 10 == info6.fBounds.fTop);
1075             REPORTER_ASSERT(reporter, info6.fLocalMat.isIdentity());
1076             REPORTER_ASSERT(reporter, info6.fPreMat.isIdentity());
1077             REPORTER_ASSERT(reporter, info6.fPaint);
1078             REPORTER_ASSERT(reporter, !info6.fIsNested &&
1079                                       info6.fHasNestedLayers); // has a nested SL
1080
1081             REPORTER_ASSERT(reporter, child == info7.fPicture); // in a child picture
1082             REPORTER_ASSERT(reporter, kWidth == info7.fBounds.width() &&
1083                                       kHeight == info7.fBounds.height());
1084             REPORTER_ASSERT(reporter, 0 == info7.fBounds.fLeft && 0 == info7.fBounds.fTop);
1085             REPORTER_ASSERT(reporter, info7.fLocalMat.isIdentity());
1086             REPORTER_ASSERT(reporter, info7.fPreMat.isIdentity());
1087             REPORTER_ASSERT(reporter, NULL != info7.fPaint);
1088             REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested
1089         }
1090     }
1091 }
1092
1093 #endif
1094
1095 static void test_has_text(skiatest::Reporter* reporter) {
1096     SkPictureRecorder recorder;
1097
1098     SkCanvas* canvas = recorder.beginRecording(100,100);
1099     {
1100         canvas->drawRect(SkRect::MakeWH(20, 20), SkPaint());
1101     }
1102     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1103     REPORTER_ASSERT(reporter, !picture->hasText());
1104
1105     SkPoint point = SkPoint::Make(10, 10);
1106     canvas = recorder.beginRecording(100,100);
1107     {
1108         canvas->drawText("Q", 1, point.fX, point.fY, SkPaint());
1109     }
1110     picture.reset(recorder.endRecording());
1111     REPORTER_ASSERT(reporter, picture->hasText());
1112
1113     canvas = recorder.beginRecording(100,100);
1114     {
1115         canvas->drawPosText("Q", 1, &point, SkPaint());
1116     }
1117     picture.reset(recorder.endRecording());
1118     REPORTER_ASSERT(reporter, picture->hasText());
1119
1120     canvas = recorder.beginRecording(100,100);
1121     {
1122         canvas->drawPosTextH("Q", 1, &point.fX, point.fY, SkPaint());
1123     }
1124     picture.reset(recorder.endRecording());
1125     REPORTER_ASSERT(reporter, picture->hasText());
1126
1127     canvas = recorder.beginRecording(100,100);
1128     {
1129         SkPath path;
1130         path.moveTo(0, 0);
1131         path.lineTo(50, 50);
1132
1133         canvas->drawTextOnPathHV("Q", 1, path, point.fX, point.fY, SkPaint());
1134     }
1135     picture.reset(recorder.endRecording());
1136     REPORTER_ASSERT(reporter, picture->hasText());
1137
1138     canvas = recorder.beginRecording(100,100);
1139     {
1140         SkPath path;
1141         path.moveTo(0, 0);
1142         path.lineTo(50, 50);
1143
1144         canvas->drawTextOnPath("Q", 1, path, NULL, SkPaint());
1145     }
1146     picture.reset(recorder.endRecording());
1147     REPORTER_ASSERT(reporter, picture->hasText());
1148
1149     // Nest the previous picture inside a new one.
1150     canvas = recorder.beginRecording(100,100);
1151     {
1152         canvas->drawPicture(picture.get());
1153     }
1154     picture.reset(recorder.endRecording());
1155     REPORTER_ASSERT(reporter, picture->hasText());
1156 }
1157
1158 static void set_canvas_to_save_count_4(SkCanvas* canvas) {
1159     canvas->restoreToCount(1);
1160     canvas->save();
1161     canvas->save();
1162     canvas->save();
1163 }
1164
1165 /**
1166  * A canvas that records the number of saves, saveLayers and restores.
1167  */
1168 class SaveCountingCanvas : public SkCanvas {
1169 public:
1170     SaveCountingCanvas(int width, int height)
1171         : INHERITED(width, height)
1172         , fSaveCount(0)
1173         , fSaveLayerCount(0)
1174         , fRestoreCount(0){
1175     }
1176
1177     virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint,
1178                                             SaveFlags flags) SK_OVERRIDE {
1179         ++fSaveLayerCount;
1180         return this->INHERITED::willSaveLayer(bounds, paint, flags);
1181     }
1182
1183     virtual void willSave() SK_OVERRIDE {
1184         ++fSaveCount;
1185         this->INHERITED::willSave();
1186     }
1187
1188     virtual void willRestore() SK_OVERRIDE {
1189         ++fRestoreCount;
1190         this->INHERITED::willRestore();
1191     }
1192
1193     unsigned int getSaveCount() const { return fSaveCount; }
1194     unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
1195     unsigned int getRestoreCount() const { return fRestoreCount; }
1196
1197 private:
1198     unsigned int fSaveCount;
1199     unsigned int fSaveLayerCount;
1200     unsigned int fRestoreCount;
1201
1202     typedef SkCanvas INHERITED;
1203 };
1204
1205 void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
1206                       unsigned int numSaves, unsigned int numSaveLayers,
1207                       unsigned int numRestores) {
1208     SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
1209                               SkScalarCeilToInt(picture->cullRect().height()));
1210
1211     picture->playback(&canvas);
1212
1213     // Optimizations may have removed these,
1214     // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
1215     REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
1216     REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
1217     REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
1218 }
1219
1220 // This class exists so SkPicture can friend it and give it access to
1221 // the 'partialReplay' method.
1222 class SkPictureRecorderReplayTester {
1223 public:
1224     static SkPicture* Copy(SkPictureRecorder* recorder) {
1225         SkPictureRecorder recorder2;
1226
1227         SkCanvas* canvas = recorder2.beginRecording(10, 10);
1228
1229         recorder->partialReplay(canvas);
1230
1231         return recorder2.endRecording();
1232     }
1233 };
1234
1235 static void create_imbalance(SkCanvas* canvas) {
1236     SkRect clipRect = SkRect::MakeWH(2, 2);
1237     SkRect drawRect = SkRect::MakeWH(10, 10);
1238     canvas->save();
1239         canvas->clipRect(clipRect, SkRegion::kReplace_Op);
1240         canvas->translate(1.0f, 1.0f);
1241         SkPaint p;
1242         p.setColor(SK_ColorGREEN);
1243         canvas->drawRect(drawRect, p);
1244     // no restore
1245 }
1246
1247 // This tests that replaying a potentially unbalanced picture into a canvas
1248 // doesn't affect the canvas' save count or matrix/clip state.
1249 static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
1250     SkBitmap bm;
1251     bm.allocN32Pixels(4, 3);
1252     SkCanvas canvas(bm);
1253
1254     int beforeSaveCount = canvas.getSaveCount();
1255
1256     SkMatrix beforeMatrix = canvas.getTotalMatrix();
1257
1258     SkRect beforeClip;
1259
1260     canvas.getClipBounds(&beforeClip);
1261
1262     canvas.drawPicture(picture);
1263
1264     REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
1265     REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
1266
1267     SkRect afterClip;
1268
1269     canvas.getClipBounds(&afterClip);
1270
1271     REPORTER_ASSERT(reporter, afterClip == beforeClip);
1272 }
1273
1274 // Test out SkPictureRecorder::partialReplay
1275 DEF_TEST(PictureRecorder_replay, reporter) {
1276     // check save/saveLayer state
1277     {
1278         SkPictureRecorder recorder;
1279
1280         SkCanvas* canvas = recorder.beginRecording(10, 10);
1281
1282         canvas->saveLayer(NULL, NULL);
1283
1284         SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
1285
1286         // The extra save and restore comes from the Copy process.
1287         check_save_state(reporter, copy, 2, 1, 3);
1288
1289         canvas->saveLayer(NULL, NULL);
1290
1291         SkAutoTUnref<SkPicture> final(recorder.endRecording());
1292
1293         check_save_state(reporter, final, 1, 2, 3);
1294
1295         // The copy shouldn't pick up any operations added after it was made
1296         check_save_state(reporter, copy, 2, 1, 3);
1297     }
1298
1299     // (partially) check leakage of draw ops
1300     {
1301         SkPictureRecorder recorder;
1302
1303         SkCanvas* canvas = recorder.beginRecording(10, 10);
1304
1305         SkRect r = SkRect::MakeWH(5, 5);
1306         SkPaint p;
1307
1308         canvas->drawRect(r, p);
1309
1310         SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
1311
1312         REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
1313
1314         SkBitmap bm;
1315         make_bm(&bm, 10, 10, SK_ColorRED, true);
1316
1317         r.offset(5.0f, 5.0f);
1318         canvas->drawBitmapRectToRect(bm, NULL, r);
1319
1320         SkAutoTUnref<SkPicture> final(recorder.endRecording());
1321         REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
1322
1323         REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
1324
1325         // The snapshot shouldn't pick up any operations added after it was made
1326         REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
1327     }
1328
1329     // Recreate the Android partialReplay test case
1330     {
1331         SkPictureRecorder recorder;
1332
1333         SkCanvas* canvas = recorder.beginRecording(4, 3, NULL, 0);
1334         create_imbalance(canvas);
1335
1336         int expectedSaveCount = canvas->getSaveCount();
1337
1338         SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
1339         check_balance(reporter, copy);
1340
1341         REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
1342
1343         // End the recording of source to test the picture finalization
1344         // process isn't complicated by the partialReplay step
1345         SkAutoTUnref<SkPicture> final(recorder.endRecording());
1346     }
1347 }
1348
1349 static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
1350     SkCanvas testCanvas(100, 100);
1351     set_canvas_to_save_count_4(&testCanvas);
1352
1353     REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
1354
1355     SkPaint paint;
1356     SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
1357
1358     SkPictureRecorder recorder;
1359
1360     {
1361         // Create picture with 2 unbalanced saves
1362         SkCanvas* canvas = recorder.beginRecording(100, 100);
1363         canvas->save();
1364         canvas->translate(10, 10);
1365         canvas->drawRect(rect, paint);
1366         canvas->save();
1367         canvas->translate(10, 10);
1368         canvas->drawRect(rect, paint);
1369         SkAutoTUnref<SkPicture> extraSavePicture(recorder.endRecording());
1370
1371         testCanvas.drawPicture(extraSavePicture);
1372         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
1373     }
1374
1375     set_canvas_to_save_count_4(&testCanvas);
1376
1377     {
1378         // Create picture with 2 unbalanced restores
1379         SkCanvas* canvas = recorder.beginRecording(100, 100);
1380         canvas->save();
1381         canvas->translate(10, 10);
1382         canvas->drawRect(rect, paint);
1383         canvas->save();
1384         canvas->translate(10, 10);
1385         canvas->drawRect(rect, paint);
1386         canvas->restore();
1387         canvas->restore();
1388         canvas->restore();
1389         canvas->restore();
1390         SkAutoTUnref<SkPicture> extraRestorePicture(recorder.endRecording());
1391
1392         testCanvas.drawPicture(extraRestorePicture);
1393         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
1394     }
1395
1396     set_canvas_to_save_count_4(&testCanvas);
1397
1398     {
1399         SkCanvas* canvas = recorder.beginRecording(100, 100);
1400         canvas->translate(10, 10);
1401         canvas->drawRect(rect, paint);
1402         SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording());
1403
1404         testCanvas.drawPicture(noSavePicture);
1405         REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
1406         REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
1407     }
1408 }
1409
1410 static void test_peephole() {
1411     SkRandom rand;
1412
1413     SkPictureRecorder recorder;
1414
1415     for (int j = 0; j < 100; j++) {
1416         SkRandom rand2(rand); // remember the seed
1417
1418         SkCanvas* canvas = recorder.beginRecording(100, 100);
1419
1420         for (int i = 0; i < 1000; ++i) {
1421             rand_op(canvas, rand);
1422         }
1423         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1424
1425         rand = rand2;
1426     }
1427
1428     {
1429         SkCanvas* canvas = recorder.beginRecording(100, 100);
1430         SkRect rect = SkRect::MakeWH(50, 50);
1431
1432         for (int i = 0; i < 100; ++i) {
1433             canvas->save();
1434         }
1435         while (canvas->getSaveCount() > 1) {
1436             canvas->clipRect(rect);
1437             canvas->restore();
1438         }
1439         SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1440     }
1441 }
1442
1443 #ifndef SK_DEBUG
1444 // Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
1445 // should never do this.
1446 static void test_bad_bitmap() {
1447     // This bitmap has a width and height but no pixels. As a result, attempting to record it will
1448     // fail.
1449     SkBitmap bm;
1450     bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
1451     SkPictureRecorder recorder;
1452     SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
1453     recordingCanvas->drawBitmap(bm, 0, 0);
1454     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1455
1456     SkCanvas canvas;
1457     canvas.drawPicture(picture);
1458 }
1459 #endif
1460
1461 static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) {
1462     return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
1463 }
1464
1465 static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
1466     SkPictureRecorder recorder;
1467     SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bitmap.width()),
1468                                                SkIntToScalar(bitmap.height()));
1469     canvas->drawBitmap(bitmap, 0, 0);
1470     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1471
1472     SkDynamicMemoryWStream wStream;
1473     picture->serialize(&wStream, &encode_bitmap_to_data);
1474     return wStream.copyToData();
1475 }
1476
1477 struct ErrorContext {
1478     int fErrors;
1479     skiatest::Reporter* fReporter;
1480 };
1481
1482 static void assert_one_parse_error_cb(SkError error, void* context) {
1483     ErrorContext* errorContext = static_cast<ErrorContext*>(context);
1484     errorContext->fErrors++;
1485     // This test only expects one error, and that is a kParseError. If there are others,
1486     // there is some unknown problem.
1487     REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors,
1488                             "This threw more errors than expected.");
1489     REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error,
1490                             SkGetLastErrorString());
1491 }
1492
1493 static void test_bitmap_with_encoded_data(skiatest::Reporter* reporter) {
1494     // Create a bitmap that will be encoded.
1495     SkBitmap original;
1496     make_bm(&original, 100, 100, SK_ColorBLUE, true);
1497     SkDynamicMemoryWStream wStream;
1498     if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
1499         return;
1500     }
1501     SkAutoDataUnref data(wStream.copyToData());
1502
1503     SkBitmap bm;
1504     bool installSuccess = SkInstallDiscardablePixelRef(
1505          SkDecodingImageGenerator::Create(data, SkDecodingImageGenerator::Options()), &bm);
1506     REPORTER_ASSERT(reporter, installSuccess);
1507
1508     // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
1509     // Flattening original will follow the old path of performing an encode, while flattening bm
1510     // will use the already encoded data.
1511     SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
1512     SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
1513     REPORTER_ASSERT(reporter, picture1->equals(picture2));
1514     // Now test that a parse error was generated when trying to create a new SkPicture without
1515     // providing a function to decode the bitmap.
1516     ErrorContext context;
1517     context.fErrors = 0;
1518     context.fReporter = reporter;
1519     SkSetErrorCallback(assert_one_parse_error_cb, &context);
1520     SkMemoryStream pictureStream(picture1);
1521     SkClearLastError();
1522     SkAutoUnref pictureFromStream(SkPicture::CreateFromStream(&pictureStream, NULL));
1523     REPORTER_ASSERT(reporter, pictureFromStream.get() != NULL);
1524     SkClearLastError();
1525     SkSetErrorCallback(NULL, NULL);
1526 }
1527
1528 static void test_clip_bound_opt(skiatest::Reporter* reporter) {
1529     // Test for crbug.com/229011
1530     SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
1531                                     SkIntToScalar(2), SkIntToScalar(2));
1532     SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
1533                                     SkIntToScalar(1), SkIntToScalar(1));
1534     SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
1535                                     SkIntToScalar(1), SkIntToScalar(1));
1536
1537     SkPath invPath;
1538     invPath.addOval(rect1);
1539     invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1540     SkPath path;
1541     path.addOval(rect2);
1542     SkPath path2;
1543     path2.addOval(rect3);
1544     SkIRect clipBounds;
1545     SkPictureRecorder recorder;
1546
1547     // Testing conservative-raster-clip that is enabled by PictureRecord
1548     {
1549         SkCanvas* canvas = recorder.beginRecording(10, 10);
1550         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
1551         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1552         REPORTER_ASSERT(reporter, true == nonEmpty);
1553         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
1554         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
1555         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
1556         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
1557     }
1558     {
1559         SkCanvas* canvas = recorder.beginRecording(10, 10);
1560         canvas->clipPath(path, SkRegion::kIntersect_Op);
1561         canvas->clipPath(invPath, SkRegion::kIntersect_Op);
1562         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1563         REPORTER_ASSERT(reporter, true == nonEmpty);
1564         REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
1565         REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
1566         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1567         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1568     }
1569     {
1570         SkCanvas* canvas = recorder.beginRecording(10, 10);
1571         canvas->clipPath(path, SkRegion::kIntersect_Op);
1572         canvas->clipPath(invPath, SkRegion::kUnion_Op);
1573         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1574         REPORTER_ASSERT(reporter, true == nonEmpty);
1575         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
1576         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
1577         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
1578         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
1579     }
1580     {
1581         SkCanvas* canvas = recorder.beginRecording(10, 10);
1582         canvas->clipPath(path, SkRegion::kDifference_Op);
1583         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1584         REPORTER_ASSERT(reporter, true == nonEmpty);
1585         REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
1586         REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
1587         REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
1588         REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
1589     }
1590     {
1591         SkCanvas* canvas = recorder.beginRecording(10, 10);
1592         canvas->clipPath(path, SkRegion::kReverseDifference_Op);
1593         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1594         // True clip is actually empty in this case, but the best
1595         // determination we can make using only bounds as input is that the
1596         // clip is included in the bounds of 'path'.
1597         REPORTER_ASSERT(reporter, true == nonEmpty);
1598         REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
1599         REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
1600         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1601         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1602     }
1603     {
1604         SkCanvas* canvas = recorder.beginRecording(10, 10);
1605         canvas->clipPath(path, SkRegion::kIntersect_Op);
1606         canvas->clipPath(path2, SkRegion::kXOR_Op);
1607         bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1608         REPORTER_ASSERT(reporter, true == nonEmpty);
1609         REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
1610         REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
1611         REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1612         REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1613     }
1614 }
1615
1616 /**
1617  * A canvas that records the number of clip commands.
1618  */
1619 class ClipCountingCanvas : public SkCanvas {
1620 public:
1621     ClipCountingCanvas(int width, int height)
1622         : INHERITED(width, height)
1623         , fClipCount(0){
1624     }
1625
1626     virtual void onClipRect(const SkRect& r,
1627                             SkRegion::Op op,
1628                             ClipEdgeStyle edgeStyle) SK_OVERRIDE {
1629         fClipCount += 1;
1630         this->INHERITED::onClipRect(r, op, edgeStyle);
1631     }
1632
1633     virtual void onClipRRect(const SkRRect& rrect,
1634                              SkRegion::Op op,
1635                              ClipEdgeStyle edgeStyle)SK_OVERRIDE {
1636         fClipCount += 1;
1637         this->INHERITED::onClipRRect(rrect, op, edgeStyle);
1638     }
1639
1640     virtual void onClipPath(const SkPath& path,
1641                             SkRegion::Op op,
1642                             ClipEdgeStyle edgeStyle) SK_OVERRIDE {
1643         fClipCount += 1;
1644         this->INHERITED::onClipPath(path, op, edgeStyle);
1645     }
1646
1647     virtual void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) SK_OVERRIDE {
1648         fClipCount += 1;
1649         this->INHERITED::onClipRegion(deviceRgn, op);
1650     }
1651
1652     unsigned getClipCount() const { return fClipCount; }
1653
1654 private:
1655     unsigned fClipCount;
1656
1657     typedef SkCanvas INHERITED;
1658 };
1659
1660 static void test_clip_expansion(skiatest::Reporter* reporter) {
1661     SkPictureRecorder recorder;
1662     SkCanvas* canvas = recorder.beginRecording(10, 10);
1663
1664     canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
1665     // The following expanding clip should not be skipped.
1666     canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
1667     // Draw something so the optimizer doesn't just fold the world.
1668     SkPaint p;
1669     p.setColor(SK_ColorBLUE);
1670     canvas->drawPaint(p);
1671     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1672
1673     ClipCountingCanvas testCanvas(10, 10);
1674     picture->playback(&testCanvas);
1675
1676     // Both clips should be present on playback.
1677     REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
1678 }
1679
1680 static void test_hierarchical(skiatest::Reporter* reporter) {
1681     SkBitmap bm;
1682     make_bm(&bm, 10, 10, SK_ColorRED, true);
1683
1684     SkPictureRecorder recorder;
1685
1686     recorder.beginRecording(10, 10);
1687     SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
1688     REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
1689
1690     recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
1691     SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
1692     REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
1693
1694     {
1695         SkCanvas* canvas = recorder.beginRecording(10, 10);
1696         canvas->drawPicture(childPlain);
1697         SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
1698         REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
1699     }
1700     {
1701         SkCanvas* canvas = recorder.beginRecording(10, 10);
1702         canvas->drawPicture(childWithBitmap);
1703         SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
1704         REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
1705     }
1706     {
1707         SkCanvas* canvas = recorder.beginRecording(10, 10);
1708         canvas->drawBitmap(bm, 0, 0);
1709         canvas->drawPicture(childPlain);
1710         SkAutoTUnref<SkPicture> parentWBP(recorder.endRecording());
1711         REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
1712     }
1713     {
1714         SkCanvas* canvas = recorder.beginRecording(10, 10);
1715         canvas->drawBitmap(bm, 0, 0);
1716         canvas->drawPicture(childWithBitmap);
1717         SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
1718         REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
1719     }
1720 }
1721
1722 static void test_gen_id(skiatest::Reporter* reporter) {
1723
1724     SkPictureRecorder recorder;
1725     recorder.beginRecording(0, 0);
1726     SkAutoTUnref<SkPicture> empty(recorder.endRecording());
1727
1728     // Empty pictures should still have a valid ID
1729     REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
1730
1731     SkCanvas* canvas = recorder.beginRecording(1, 1);
1732     canvas->drawARGB(255, 255, 255, 255);
1733     SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
1734     // picture should have a non-zero id after recording
1735     REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
1736
1737     // both pictures should have different ids
1738     REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
1739 }
1740
1741 DEF_TEST(Picture, reporter) {
1742 #ifdef SK_DEBUG
1743     test_deleting_empty_picture();
1744     test_serializing_empty_picture();
1745 #else
1746     test_bad_bitmap();
1747 #endif
1748     test_unbalanced_save_restores(reporter);
1749     test_peephole();
1750 #if SK_SUPPORT_GPU
1751     test_gpu_veto(reporter);
1752 #endif
1753     test_has_text(reporter);
1754     test_analysis(reporter);
1755     test_gatherpixelrefs(reporter);
1756     test_gatherpixelrefsandrects(reporter);
1757     test_bitmap_with_encoded_data(reporter);
1758     test_clip_bound_opt(reporter);
1759     test_clip_expansion(reporter);
1760     test_hierarchical(reporter);
1761     test_gen_id(reporter);
1762 }
1763
1764 #if SK_SUPPORT_GPU
1765 DEF_GPUTEST(GPUPicture, reporter, factory) {
1766     test_gpu_picture_optimization(reporter, factory);
1767 }
1768 #endif
1769
1770 static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
1771     const SkPaint paint;
1772     const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
1773     const SkIRect irect =  { 2, 2, 3, 3 };
1774
1775     // Don't care what these record, as long as they're legal.
1776     canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
1777     canvas->drawBitmapRectToRect(bitmap, &rect, rect, &paint, SkCanvas::kNone_DrawBitmapRectFlag);
1778     canvas->drawBitmapMatrix(bitmap, SkMatrix::I(), &paint);
1779     canvas->drawBitmapNine(bitmap, irect, rect, &paint);
1780     canvas->drawSprite(bitmap, 1, 1);
1781 }
1782
1783 static void test_draw_bitmaps(SkCanvas* canvas) {
1784     SkBitmap empty;
1785     draw_bitmaps(empty, canvas);
1786     empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
1787     draw_bitmaps(empty, canvas);
1788 }
1789
1790 DEF_TEST(Picture_EmptyBitmap, r) {
1791     SkPictureRecorder recorder;
1792     test_draw_bitmaps(recorder.beginRecording(10, 10));
1793     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1794 }
1795
1796 DEF_TEST(Canvas_EmptyBitmap, r) {
1797     SkBitmap dst;
1798     dst.allocN32Pixels(10, 10);
1799     SkCanvas canvas(dst);
1800
1801     test_draw_bitmaps(&canvas);
1802 }
1803
1804 DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
1805     // This test is from crbug.com/344987.
1806     // The commands are:
1807     //   saveLayer with paint that modifies alpha
1808     //     drawBitmapRectToRect
1809     //     drawBitmapRectToRect
1810     //   restore
1811     // The bug was that this structure was modified so that:
1812     //  - The saveLayer and restore were eliminated
1813     //  - The alpha was only applied to the first drawBitmapRectToRect
1814
1815     // This test draws blue and red squares inside a 50% transparent
1816     // layer.  Both colours should show up muted.
1817     // When the bug is present, the red square (the second bitmap)
1818     // shows upwith full opacity.
1819
1820     SkBitmap blueBM;
1821     make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
1822     SkBitmap redBM;
1823     make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
1824     SkPaint semiTransparent;
1825     semiTransparent.setAlpha(0x80);
1826
1827     SkPictureRecorder recorder;
1828     SkCanvas* canvas = recorder.beginRecording(100, 100);
1829     canvas->drawARGB(0, 0, 0, 0);
1830
1831     canvas->saveLayer(0, &semiTransparent);
1832     canvas->drawBitmap(blueBM, 25, 25);
1833     canvas->drawBitmap(redBM, 50, 50);
1834     canvas->restore();
1835
1836     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1837
1838     // Now replay the picture back on another canvas
1839     // and check a couple of its pixels.
1840     SkBitmap replayBM;
1841     make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
1842     SkCanvas replayCanvas(replayBM);
1843     picture->playback(&replayCanvas);
1844     replayCanvas.flush();
1845
1846     // With the bug present, at (55, 55) we would get a fully opaque red
1847     // intead of a dark red.
1848     REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
1849     REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
1850 }
1851
1852 struct CountingBBH : public SkBBoxHierarchy {
1853     mutable int searchCalls;
1854
1855     CountingBBH() : searchCalls(0) {}
1856
1857     virtual void search(const SkRect& query, SkTDArray<unsigned>* results) const SK_OVERRIDE {
1858         this->searchCalls++;
1859     }
1860
1861     virtual void insert(SkAutoTMalloc<SkRect>*, int) SK_OVERRIDE {}
1862 };
1863
1864 class SpoonFedBBHFactory : public SkBBHFactory {
1865 public:
1866     explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
1867     virtual SkBBoxHierarchy* operator()(int width, int height) const {
1868         return SkRef(fBBH);
1869     }
1870 private:
1871     SkBBoxHierarchy* fBBH;
1872 };
1873
1874 // When the canvas clip covers the full picture, we don't need to call the BBH.
1875 DEF_TEST(Picture_SkipBBH, r) {
1876     CountingBBH bbh;
1877     SpoonFedBBHFactory factory(&bbh);
1878
1879     SkPictureRecorder recorder;
1880     recorder.beginRecording(320, 240, &factory);
1881     SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
1882
1883     SkCanvas big(640, 480), small(300, 200);
1884
1885     picture->playback(&big);
1886     REPORTER_ASSERT(r, bbh.searchCalls == 0);
1887
1888     picture->playback(&small);
1889     REPORTER_ASSERT(r, bbh.searchCalls == 1);
1890 }
1891
1892 DEF_TEST(Picture_BitmapLeak, r) {
1893     SkBitmap mut, immut;
1894     mut.allocN32Pixels(300, 200);
1895     immut.allocN32Pixels(300, 200);
1896     immut.setImmutable();
1897     SkASSERT(!mut.isImmutable());
1898     SkASSERT(immut.isImmutable());
1899
1900     // No one can hold a ref on our pixels yet.
1901     REPORTER_ASSERT(r, mut.pixelRef()->unique());
1902     REPORTER_ASSERT(r, immut.pixelRef()->unique());
1903
1904     SkPictureRecorder rec;
1905     SkCanvas* canvas = rec.beginRecording(1920, 1200);
1906         canvas->drawBitmap(mut, 0, 0);
1907         canvas->drawBitmap(immut, 800, 600);
1908     SkAutoTDelete<const SkPicture> pic(rec.endRecording());
1909
1910     // The picture shares the immutable pixels but copies the mutable ones.
1911     REPORTER_ASSERT(r, mut.pixelRef()->unique());
1912     REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1913
1914     // When the picture goes away, it's just our bitmaps holding the refs.
1915     pic.reset(NULL);
1916     REPORTER_ASSERT(r, mut.pixelRef()->unique());
1917     REPORTER_ASSERT(r, immut.pixelRef()->unique());
1918 }