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