PictureTest.cpp revision 0205aba7d5e8802d2a3ef55d999f5aa41db3adc9
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 "SkBitmapDevice.h"
9#if SK_SUPPORT_GPU
10#include "SkBlurImageFilter.h"
11#endif
12#include "SkCanvas.h"
13#include "SkColorPriv.h"
14#include "SkDashPathEffect.h"
15#include "SkData.h"
16#include "SkDecodingImageGenerator.h"
17#include "SkError.h"
18#if SK_SUPPORT_GPU
19#include "SkGpuDevice.h"
20#endif
21#include "SkImageEncoder.h"
22#include "SkImageGenerator.h"
23#include "SkPaint.h"
24#include "SkPicture.h"
25#include "SkPictureRecorder.h"
26#include "SkPictureUtils.h"
27#include "SkRRect.h"
28#include "SkRandom.h"
29#include "SkShader.h"
30#include "SkStream.h"
31
32#if SK_SUPPORT_GPU
33#include "SkSurface.h"
34#include "GrContextFactory.h"
35#include "GrPictureUtils.h"
36#endif
37#include "Test.h"
38
39static const int gColorScale = 30;
40static const int gColorOffset = 60;
41
42static 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
50static 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
73static 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
80typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&,
81                               const SkBitmap&, const SkPoint&,
82                               SkTDArray<SkPixelRef*>* usedPixRefs);
83
84static 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
94static 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
113static 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
126static 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
139static 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
154static 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
170static 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
177static 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
189static 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).
204static 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
221static 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
231static 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
248static 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
259static 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
271static 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
287static 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.
311static 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, NULL, 0);
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
331static 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
344static 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
351template <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[]
361static 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.
371static 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
418static 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
433static 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
457static 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
478static 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
583static void test_gatherpixelrefsandrects(skiatest::Reporter* reporter) {
584    const int IW = 32;
585    const int IH = IW;
586    const SkScalar W = SkIntToScalar(IW);
587    const SkScalar H = W;
588
589    static const int N = 4;
590    SkBitmap bm[2*N];
591    SkPixelRef* refs[2*N];
592    SkTDArray<SkPixelRef*> analytic[N];
593
594    const SkPoint pos[N] = {
595        { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
596    };
597
598    create_textures(bm, refs, N, IW, IH);
599
600    SkRandom rand;
601    for (size_t k = 0; k < SK_ARRAY_COUNT(gProcs); ++k) {
602        SkAutoTUnref<SkPicture> pic(
603            record_bitmaps(bm, pos, analytic, N, gProcs[k].proc));
604
605        REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0);
606
607        SkAutoTUnref<SkPictureUtils::SkPixelRefContainer> prCont(
608                                new SkPictureUtils::SkPixelRefsAndRectsList);
609
610        SkPictureUtils::GatherPixelRefsAndRects(pic, prCont);
611
612        // quick check for a small piece of each quadrant, which should just
613        // contain 1 or 2 bitmaps.
614        for (size_t  i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
615            SkRect r;
616            r.set(2, 2, W - 2, H - 2);
617            r.offset(pos[i].fX, pos[i].fY);
618
619            SkTDArray<SkPixelRef*> gatheredRefs;
620            prCont->query(r, &gatheredRefs);
621
622            int count = gatheredRefs.count();
623            REPORTER_ASSERT(reporter, 1 == count || 2 == count);
624            if (1 == count) {
625                REPORTER_ASSERT(reporter, gatheredRefs[0] == refs[i]);
626            } else if (2 == count) {
627                REPORTER_ASSERT(reporter,
628                    (gatheredRefs[0] == refs[i] && gatheredRefs[1] == refs[i+N]) ||
629                    (gatheredRefs[1] == refs[i] && gatheredRefs[0] == refs[i+N]));
630            }
631        }
632
633        SkBitmap image;
634        draw(pic, 2*IW, 2*IH, &image);
635
636        // Test a bunch of random (mostly) rects, and compare the gather results
637        // with the analytic results and the pixel refs seen in a rendering.
638        for (int j = 0; j < 100; ++j) {
639            SkRect r;
640            rand_rect(&r, rand, 2*W, 2*H);
641
642            SkTDArray<SkPixelRef*> fromImage;
643            gather_from_image(image, refs, N, &fromImage, r);
644
645            SkTDArray<SkPixelRef*> fromAnalytic;
646            gather_from_analytic(pos, W, H, analytic, N, &fromAnalytic, r);
647
648            SkTDArray<SkPixelRef*> gatheredRefs;
649            prCont->query(r, &gatheredRefs);
650
651            // Everything that we saw drawn should appear in the analytic list
652            // but the analytic list may contain some pixelRefs that were not
653            // seen in the image (e.g., A8 textures used as masks)
654            for (int i = 0; i < fromImage.count(); ++i) {
655                REPORTER_ASSERT(reporter, -1 != fromAnalytic.find(fromImage[i]));
656            }
657
658            // Everything in the analytic list should appear in the gathered
659            // list.
660            for (int i = 0; i < fromAnalytic.count(); ++i) {
661                REPORTER_ASSERT(reporter, -1 != gatheredRefs.find(fromAnalytic[i]));
662            }
663        }
664    }
665}
666
667#ifdef SK_DEBUG
668// Ensure that deleting SkPicturePlayback does not assert. Asserts only fire in debug mode, so only
669// run in debug mode.
670static void test_deleting_empty_playback() {
671    SkPictureRecorder recorder;
672    // Creates an SkPictureRecord
673    recorder.beginRecording(0, 0, NULL, 0);
674    // Turns that into an SkPicturePlayback
675    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
676    // Deletes the old SkPicturePlayback, and creates a new SkPictureRecord
677    recorder.beginRecording(0, 0, NULL, 0);
678}
679
680// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
681static void test_serializing_empty_picture() {
682    SkPictureRecorder recorder;
683    recorder.beginRecording(0, 0, NULL, 0);
684    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
685    SkDynamicMemoryWStream stream;
686    picture->serialize(&stream);
687}
688#endif
689
690static void rand_op(SkCanvas* canvas, SkRandom& rand) {
691    SkPaint paint;
692    SkRect rect = SkRect::MakeWH(50, 50);
693
694    SkScalar unit = rand.nextUScalar1();
695    if (unit <= 0.3) {
696//        SkDebugf("save\n");
697        canvas->save();
698    } else if (unit <= 0.6) {
699//        SkDebugf("restore\n");
700        canvas->restore();
701    } else if (unit <= 0.9) {
702//        SkDebugf("clip\n");
703        canvas->clipRect(rect);
704    } else {
705//        SkDebugf("draw\n");
706        canvas->drawPaint(paint);
707    }
708}
709
710#if SK_SUPPORT_GPU
711static void test_gpu_veto(skiatest::Reporter* reporter) {
712
713    SkPictureRecorder recorder;
714
715    SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
716    {
717        SkPath path;
718        path.moveTo(0, 0);
719        path.lineTo(50, 50);
720
721        SkScalar intervals[] = { 1.0f, 1.0f };
722        SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, 2, 0));
723
724        SkPaint paint;
725        paint.setStyle(SkPaint::kStroke_Style);
726        paint.setPathEffect(dash);
727
728        canvas->drawPath(path, paint);
729    }
730    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
731    // path effects currently render an SkPicture undesireable for GPU rendering
732    REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
733
734    canvas = recorder.beginRecording(100, 100, NULL, 0);
735    {
736        SkPath path;
737
738        path.moveTo(0, 0);
739        path.lineTo(0, 50);
740        path.lineTo(25, 25);
741        path.lineTo(50, 50);
742        path.lineTo(50, 0);
743        path.close();
744        REPORTER_ASSERT(reporter, !path.isConvex());
745
746        SkPaint paint;
747        paint.setAntiAlias(true);
748        for (int i = 0; i < 50; ++i) {
749            canvas->drawPath(path, paint);
750        }
751    }
752    picture.reset(recorder.endRecording());
753    // A lot of AA concave paths currently render an SkPicture undesireable for GPU rendering
754    REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(NULL));
755
756    canvas = recorder.beginRecording(100, 100, NULL, 0);
757    {
758        SkPath path;
759
760        path.moveTo(0, 0);
761        path.lineTo(0, 50);
762        path.lineTo(25, 25);
763        path.lineTo(50, 50);
764        path.lineTo(50, 0);
765        path.close();
766        REPORTER_ASSERT(reporter, !path.isConvex());
767
768        SkPaint paint;
769        paint.setAntiAlias(true);
770        paint.setStyle(SkPaint::kStroke_Style);
771        paint.setStrokeWidth(0);
772        for (int i = 0; i < 50; ++i) {
773            canvas->drawPath(path, paint);
774        }
775    }
776    picture.reset(recorder.endRecording());
777    // hairline stroked AA concave paths are fine for GPU rendering
778    REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(NULL));
779}
780
781static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
782                                          GrContextFactory* factory) {
783
784    GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
785
786    static const int kWidth = 100;
787    static const int kHeight = 100;
788
789    SkAutoTUnref<SkPicture> pict;
790
791    // create a picture with the structure:
792    // 1)
793    //      SaveLayer
794    //      Restore
795    // 2)
796    //      SaveLayer
797    //          Translate
798    //          SaveLayer w/ bound
799    //          Restore
800    //      Restore
801    // 3)
802    //      SaveLayer w/ copyable paint
803    //      Restore
804    // 4)
805    //      SaveLayer w/ non-copyable paint
806    //      Restore
807    {
808        SkPictureRecorder recorder;
809
810        SkCanvas* c = recorder.beginRecording(kWidth, kHeight, NULL, 0);
811        // 1)
812        c->saveLayer(NULL, NULL);
813        c->restore();
814
815        // 2)
816        c->saveLayer(NULL, NULL);
817            c->translate(kWidth/2, kHeight/2);
818            SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
819            c->saveLayer(&r, NULL);
820            c->restore();
821        c->restore();
822
823        // 3)
824        {
825            SkPaint p;
826            p.setColor(SK_ColorRED);
827            c->saveLayer(NULL, &p);
828            c->restore();
829        }
830        // 4)
831        // TODO: this case will need to be removed once the paint's are immutable
832        {
833            SkPaint p;
834            SkBitmap bmp;
835            bmp.allocN32Pixels(10, 10);
836            bmp.eraseColor(SK_ColorGREEN);
837            bmp.setAlphaType(kOpaque_SkAlphaType);
838            SkShader* shader = SkShader::CreateBitmapShader(bmp,
839                                    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
840            p.setShader(shader)->unref();
841
842            c->saveLayer(NULL, &p);
843            c->restore();
844        }
845
846        pict.reset(recorder.endRecording());
847    }
848
849    // Now test out the SaveLayer extraction
850    {
851        SkImageInfo info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
852
853        SkAutoTUnref<SkSurface> surface(SkSurface::NewScratchRenderTarget(context, info));
854
855        SkCanvas* canvas = surface->getCanvas();
856
857        canvas->EXPERIMENTAL_optimize(pict);
858
859        SkPicture::AccelData::Key key = GPUAccelData::ComputeAccelDataKey();
860
861        const SkPicture::AccelData* data = pict->EXPERIMENTAL_getAccelData(key);
862        REPORTER_ASSERT(reporter, NULL != data);
863
864        const GPUAccelData *gpuData = static_cast<const GPUAccelData*>(data);
865        REPORTER_ASSERT(reporter, 5 == gpuData->numSaveLayers());
866
867        const GPUAccelData::SaveLayerInfo& info0 = gpuData->saveLayerInfo(0);
868        // The parent/child layer appear in reverse order
869        const GPUAccelData::SaveLayerInfo& info1 = gpuData->saveLayerInfo(2);
870        const GPUAccelData::SaveLayerInfo& info2 = gpuData->saveLayerInfo(1);
871        const GPUAccelData::SaveLayerInfo& info3 = gpuData->saveLayerInfo(3);
872        const GPUAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(4);
873
874        REPORTER_ASSERT(reporter, info0.fValid);
875        REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth && kHeight == info0.fSize.fHeight);
876        REPORTER_ASSERT(reporter, info0.fCTM.isIdentity());
877        REPORTER_ASSERT(reporter, 0 == info0.fOffset.fX && 0 == info0.fOffset.fY);
878        REPORTER_ASSERT(reporter, NULL != info0.fPaint);
879        REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
880
881        REPORTER_ASSERT(reporter, info1.fValid);
882        REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth && kHeight == info1.fSize.fHeight);
883        REPORTER_ASSERT(reporter, info1.fCTM.isIdentity());
884        REPORTER_ASSERT(reporter, 0 == info1.fOffset.fX && 0 == info1.fOffset.fY);
885        REPORTER_ASSERT(reporter, NULL != info1.fPaint);
886        REPORTER_ASSERT(reporter, !info1.fIsNested && info1.fHasNestedLayers); // has a nested SL
887
888        REPORTER_ASSERT(reporter, info2.fValid);
889        REPORTER_ASSERT(reporter, kWidth/2 == info2.fSize.fWidth &&
890                                  kHeight/2 == info2.fSize.fHeight); // bound reduces size
891        REPORTER_ASSERT(reporter, info2.fCTM.isIdentity());         // translated
892        REPORTER_ASSERT(reporter, 0 == info2.fOffset.fX && 0 == info2.fOffset.fY);
893        REPORTER_ASSERT(reporter, NULL != info1.fPaint);
894        REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
895
896        REPORTER_ASSERT(reporter, info3.fValid);
897        REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth && kHeight == info3.fSize.fHeight);
898        REPORTER_ASSERT(reporter, info3.fCTM.isIdentity());
899        REPORTER_ASSERT(reporter, 0 == info3.fOffset.fX && 0 == info3.fOffset.fY);
900        REPORTER_ASSERT(reporter, NULL != info3.fPaint);
901        REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
902
903        REPORTER_ASSERT(reporter, !info4.fValid);                 // paint is/was uncopyable
904        REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth && kHeight == info4.fSize.fHeight);
905        REPORTER_ASSERT(reporter, 0 == info4.fOffset.fX && 0 == info4.fOffset.fY);
906        REPORTER_ASSERT(reporter, info4.fCTM.isIdentity());
907        REPORTER_ASSERT(reporter, NULL == info4.fPaint);     // paint is/was uncopyable
908        REPORTER_ASSERT(reporter, !info4.fIsNested && !info4.fHasNestedLayers);
909    }
910}
911
912#endif
913
914static void set_canvas_to_save_count_4(SkCanvas* canvas) {
915    canvas->restoreToCount(1);
916    canvas->save();
917    canvas->save();
918    canvas->save();
919}
920
921static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
922    SkCanvas testCanvas(100, 100);
923    set_canvas_to_save_count_4(&testCanvas);
924
925    REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
926
927    SkPaint paint;
928    SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
929
930    SkPictureRecorder recorder;
931
932    {
933        // Create picture with 2 unbalanced saves
934        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
935        canvas->save();
936        canvas->translate(10, 10);
937        canvas->drawRect(rect, paint);
938        canvas->save();
939        canvas->translate(10, 10);
940        canvas->drawRect(rect, paint);
941        SkAutoTUnref<SkPicture> extraSavePicture(recorder.endRecording());
942
943        testCanvas.drawPicture(*extraSavePicture);
944        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
945    }
946
947    set_canvas_to_save_count_4(&testCanvas);
948
949    {
950        // Create picture with 2 unbalanced restores
951        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
952        canvas->save();
953        canvas->translate(10, 10);
954        canvas->drawRect(rect, paint);
955        canvas->save();
956        canvas->translate(10, 10);
957        canvas->drawRect(rect, paint);
958        canvas->restore();
959        canvas->restore();
960        canvas->restore();
961        canvas->restore();
962        SkAutoTUnref<SkPicture> extraRestorePicture(recorder.endRecording());
963
964        testCanvas.drawPicture(*extraRestorePicture);
965        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
966    }
967
968    set_canvas_to_save_count_4(&testCanvas);
969
970    {
971        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
972        canvas->translate(10, 10);
973        canvas->drawRect(rect, paint);
974        SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording());
975
976        testCanvas.drawPicture(*noSavePicture);
977        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
978        REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
979    }
980}
981
982static void test_peephole() {
983    SkRandom rand;
984
985    SkPictureRecorder recorder;
986
987    for (int j = 0; j < 100; j++) {
988        SkRandom rand2(rand); // remember the seed
989
990        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
991
992        for (int i = 0; i < 1000; ++i) {
993            rand_op(canvas, rand);
994        }
995        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
996
997        rand = rand2;
998    }
999
1000    {
1001        SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0);
1002        SkRect rect = SkRect::MakeWH(50, 50);
1003
1004        for (int i = 0; i < 100; ++i) {
1005            canvas->save();
1006        }
1007        while (canvas->getSaveCount() > 1) {
1008            canvas->clipRect(rect);
1009            canvas->restore();
1010        }
1011        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1012    }
1013}
1014
1015#ifndef SK_DEBUG
1016// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
1017// should never do this.
1018static void test_bad_bitmap() {
1019    // This bitmap has a width and height but no pixels. As a result, attempting to record it will
1020    // fail.
1021    SkBitmap bm;
1022    bm.setConfig(SkImageInfo::MakeN32Premul(100, 100));
1023    SkPictureRecorder recorder;
1024    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, NULL, 0);
1025    recordingCanvas->drawBitmap(bm, 0, 0);
1026    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1027
1028    SkCanvas canvas;
1029    canvas.drawPicture(*picture);
1030}
1031#endif
1032
1033static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) {
1034    return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
1035}
1036
1037static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
1038    SkPictureRecorder recorder;
1039    SkCanvas* canvas = recorder.beginRecording(bitmap.width(), bitmap.height(), NULL, 0);
1040    canvas->drawBitmap(bitmap, 0, 0);
1041    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1042
1043    SkDynamicMemoryWStream wStream;
1044    picture->serialize(&wStream, &encode_bitmap_to_data);
1045    return wStream.copyToData();
1046}
1047
1048struct ErrorContext {
1049    int fErrors;
1050    skiatest::Reporter* fReporter;
1051};
1052
1053static void assert_one_parse_error_cb(SkError error, void* context) {
1054    ErrorContext* errorContext = static_cast<ErrorContext*>(context);
1055    errorContext->fErrors++;
1056    // This test only expects one error, and that is a kParseError. If there are others,
1057    // there is some unknown problem.
1058    REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors,
1059                            "This threw more errors than expected.");
1060    REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error,
1061                            SkGetLastErrorString());
1062}
1063
1064static void test_bitmap_with_encoded_data(skiatest::Reporter* reporter) {
1065    // Create a bitmap that will be encoded.
1066    SkBitmap original;
1067    make_bm(&original, 100, 100, SK_ColorBLUE, true);
1068    SkDynamicMemoryWStream wStream;
1069    if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
1070        return;
1071    }
1072    SkAutoDataUnref data(wStream.copyToData());
1073
1074    SkBitmap bm;
1075    bool installSuccess = SkInstallDiscardablePixelRef(
1076         SkDecodingImageGenerator::Create(data, SkDecodingImageGenerator::Options()), &bm, NULL);
1077    REPORTER_ASSERT(reporter, installSuccess);
1078
1079    // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
1080    // Flattening original will follow the old path of performing an encode, while flattening bm
1081    // will use the already encoded data.
1082    SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
1083    SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
1084    REPORTER_ASSERT(reporter, picture1->equals(picture2));
1085    // Now test that a parse error was generated when trying to create a new SkPicture without
1086    // providing a function to decode the bitmap.
1087    ErrorContext context;
1088    context.fErrors = 0;
1089    context.fReporter = reporter;
1090    SkSetErrorCallback(assert_one_parse_error_cb, &context);
1091    SkMemoryStream pictureStream(picture1);
1092    SkClearLastError();
1093    SkAutoUnref pictureFromStream(SkPicture::CreateFromStream(&pictureStream, NULL));
1094    REPORTER_ASSERT(reporter, pictureFromStream.get() != NULL);
1095    SkClearLastError();
1096    SkSetErrorCallback(NULL, NULL);
1097}
1098
1099static void test_clone_empty(skiatest::Reporter* reporter) {
1100    // This is a regression test for crbug.com/172062
1101    // Before the fix, we used to crash accessing a null pointer when we
1102    // had a picture with no paints. This test passes by not crashing.
1103    {
1104        SkPictureRecorder recorder;
1105        recorder.beginRecording(1, 1, NULL, 0);
1106        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1107        SkAutoTUnref<SkPicture> destPicture(picture->clone());
1108        REPORTER_ASSERT(reporter, NULL != destPicture);
1109    }
1110}
1111
1112static void test_draw_empty(skiatest::Reporter* reporter) {
1113    SkBitmap result;
1114    make_bm(&result, 2, 2, SK_ColorBLACK, false);
1115
1116    SkCanvas canvas(result);
1117
1118    {
1119        // stock SkPicture
1120        SkPictureRecorder recorder;
1121        recorder.beginRecording(1, 1, NULL, 0);
1122        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1123
1124        canvas.drawPicture(*picture);
1125    }
1126
1127    {
1128        // tile grid
1129        SkTileGridFactory::TileGridInfo gridInfo;
1130        gridInfo.fMargin.setEmpty();
1131        gridInfo.fOffset.setZero();
1132        gridInfo.fTileInterval.set(1, 1);
1133
1134        SkTileGridFactory factory(gridInfo);
1135        SkPictureRecorder recorder;
1136        recorder.beginRecording(1, 1, &factory, 0);
1137        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1138
1139        canvas.drawPicture(*picture);
1140    }
1141
1142    {
1143        // RTree
1144        SkRTreeFactory factory;
1145        SkPictureRecorder recorder;
1146        recorder.beginRecording(1, 1, &factory, 0);
1147        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1148
1149        canvas.drawPicture(*picture);
1150    }
1151
1152    {
1153        // quad tree
1154        SkQuadTreeFactory factory;
1155        SkPictureRecorder recorder;
1156        recorder.beginRecording(1, 1, &factory, 0);
1157        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1158
1159        canvas.drawPicture(*picture);
1160    }
1161}
1162
1163static void test_clip_bound_opt(skiatest::Reporter* reporter) {
1164    // Test for crbug.com/229011
1165    SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
1166                                    SkIntToScalar(2), SkIntToScalar(2));
1167    SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
1168                                    SkIntToScalar(1), SkIntToScalar(1));
1169    SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
1170                                    SkIntToScalar(1), SkIntToScalar(1));
1171
1172    SkPath invPath;
1173    invPath.addOval(rect1);
1174    invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
1175    SkPath path;
1176    path.addOval(rect2);
1177    SkPath path2;
1178    path2.addOval(rect3);
1179    SkIRect clipBounds;
1180    SkPictureRecorder recorder;
1181    // Minimalist test set for 100% code coverage of
1182    // SkPictureRecord::updateClipConservativelyUsingBounds
1183    {
1184        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
1185            SkPicture::kUsePathBoundsForClip_RecordingFlag);
1186        canvas->clipPath(invPath, SkRegion::kIntersect_Op);
1187        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1188        REPORTER_ASSERT(reporter, true == nonEmpty);
1189        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
1190        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
1191        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
1192        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
1193    }
1194    {
1195        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
1196            SkPicture::kUsePathBoundsForClip_RecordingFlag);
1197        canvas->clipPath(path, SkRegion::kIntersect_Op);
1198        canvas->clipPath(invPath, SkRegion::kIntersect_Op);
1199        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1200        REPORTER_ASSERT(reporter, true == nonEmpty);
1201        REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
1202        REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
1203        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1204        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1205    }
1206    {
1207        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
1208            SkPicture::kUsePathBoundsForClip_RecordingFlag);
1209        canvas->clipPath(path, SkRegion::kIntersect_Op);
1210        canvas->clipPath(invPath, SkRegion::kUnion_Op);
1211        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1212        REPORTER_ASSERT(reporter, true == nonEmpty);
1213        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
1214        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
1215        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
1216        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
1217    }
1218    {
1219        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
1220            SkPicture::kUsePathBoundsForClip_RecordingFlag);
1221        canvas->clipPath(path, SkRegion::kDifference_Op);
1222        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1223        REPORTER_ASSERT(reporter, true == nonEmpty);
1224        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
1225        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
1226        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
1227        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
1228    }
1229    {
1230        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
1231            SkPicture::kUsePathBoundsForClip_RecordingFlag);
1232        canvas->clipPath(path, SkRegion::kReverseDifference_Op);
1233        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1234        // True clip is actually empty in this case, but the best
1235        // determination we can make using only bounds as input is that the
1236        // clip is included in the bounds of 'path'.
1237        REPORTER_ASSERT(reporter, true == nonEmpty);
1238        REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
1239        REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
1240        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1241        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1242    }
1243    {
1244        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL,
1245            SkPicture::kUsePathBoundsForClip_RecordingFlag);
1246        canvas->clipPath(path, SkRegion::kIntersect_Op);
1247        canvas->clipPath(path2, SkRegion::kXOR_Op);
1248        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1249        REPORTER_ASSERT(reporter, true == nonEmpty);
1250        REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
1251        REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
1252        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1253        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1254    }
1255}
1256
1257/**
1258 * A canvas that records the number of clip commands.
1259 */
1260class ClipCountingCanvas : public SkCanvas {
1261public:
1262    explicit ClipCountingCanvas(int width, int height)
1263        : INHERITED(width, height)
1264        , fClipCount(0){
1265    }
1266
1267    virtual void onClipRect(const SkRect& r,
1268                            SkRegion::Op op,
1269                            ClipEdgeStyle edgeStyle) SK_OVERRIDE {
1270        fClipCount += 1;
1271        this->INHERITED::onClipRect(r, op, edgeStyle);
1272    }
1273
1274    virtual void onClipRRect(const SkRRect& rrect,
1275                             SkRegion::Op op,
1276                             ClipEdgeStyle edgeStyle)SK_OVERRIDE {
1277        fClipCount += 1;
1278        this->INHERITED::onClipRRect(rrect, op, edgeStyle);
1279    }
1280
1281    virtual void onClipPath(const SkPath& path,
1282                            SkRegion::Op op,
1283                            ClipEdgeStyle edgeStyle) SK_OVERRIDE {
1284        fClipCount += 1;
1285        this->INHERITED::onClipPath(path, op, edgeStyle);
1286    }
1287
1288    virtual void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) SK_OVERRIDE {
1289        fClipCount += 1;
1290        this->INHERITED::onClipRegion(deviceRgn, op);
1291    }
1292
1293    unsigned getClipCount() const { return fClipCount; }
1294
1295private:
1296    unsigned fClipCount;
1297
1298    typedef SkCanvas INHERITED;
1299};
1300
1301static void test_clip_expansion(skiatest::Reporter* reporter) {
1302    SkPictureRecorder recorder;
1303    SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
1304
1305    canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
1306    // The following expanding clip should not be skipped.
1307    canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
1308    // Draw something so the optimizer doesn't just fold the world.
1309    SkPaint p;
1310    p.setColor(SK_ColorBLUE);
1311    canvas->drawPaint(p);
1312    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1313
1314    ClipCountingCanvas testCanvas(10, 10);
1315    picture->draw(&testCanvas);
1316
1317    // Both clips should be present on playback.
1318    REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
1319}
1320
1321static void test_hierarchical(skiatest::Reporter* reporter) {
1322    SkBitmap bm;
1323    make_bm(&bm, 10, 10, SK_ColorRED, true);
1324
1325    SkPictureRecorder recorder;
1326
1327    recorder.beginRecording(10, 10, NULL, 0);
1328    SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
1329    REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
1330
1331    recorder.beginRecording(10, 10, NULL, 0)->drawBitmap(bm, 0, 0);
1332    SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
1333    REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
1334
1335    {
1336        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
1337        canvas->drawPicture(*childPlain);
1338        SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
1339        REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
1340    }
1341    {
1342        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
1343        canvas->drawPicture(*childWithBitmap);
1344        SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
1345        REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
1346    }
1347    {
1348        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
1349        canvas->drawBitmap(bm, 0, 0);
1350        canvas->drawPicture(*childPlain);
1351        SkAutoTUnref<SkPicture> parentWBP(recorder.endRecording());
1352        REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
1353    }
1354    {
1355        SkCanvas* canvas = recorder.beginRecording(10, 10, NULL, 0);
1356        canvas->drawBitmap(bm, 0, 0);
1357        canvas->drawPicture(*childWithBitmap);
1358        SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
1359        REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
1360    }
1361}
1362
1363static void test_gen_id(skiatest::Reporter* reporter) {
1364
1365    SkPicture empty;
1366
1367    // Empty pictures should still have a valid ID
1368    REPORTER_ASSERT(reporter, empty.uniqueID() != SK_InvalidGenID);
1369
1370    SkPictureRecorder recorder;
1371
1372    SkCanvas* canvas = recorder.beginRecording(1, 1, NULL, 0);
1373    canvas->drawARGB(255, 255, 255, 255);
1374    SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
1375    // picture should have a non-zero id after recording
1376    REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
1377
1378    // both pictures should have different ids
1379    REPORTER_ASSERT(reporter, hasData->uniqueID() != empty.uniqueID());
1380
1381    // test out copy constructor
1382    SkPicture copyWithData(*hasData);
1383    REPORTER_ASSERT(reporter, hasData->uniqueID() == copyWithData.uniqueID());
1384
1385    SkPicture emptyCopy(empty);
1386    REPORTER_ASSERT(reporter, empty.uniqueID() != emptyCopy.uniqueID());
1387
1388    // test out swap
1389    {
1390        SkPicture swapWithData;
1391        uint32_t beforeID1 = swapWithData.uniqueID();
1392        uint32_t beforeID2 = copyWithData.uniqueID();
1393        swapWithData.swap(copyWithData);
1394        REPORTER_ASSERT(reporter, copyWithData.uniqueID() == beforeID1);
1395        REPORTER_ASSERT(reporter, swapWithData.uniqueID() == beforeID2);
1396    }
1397
1398    // test out clone
1399    {
1400        SkAutoTUnref<SkPicture> cloneWithData(hasData->clone());
1401        REPORTER_ASSERT(reporter, hasData->uniqueID() == cloneWithData->uniqueID());
1402
1403        SkAutoTUnref<SkPicture> emptyClone(empty.clone());
1404        REPORTER_ASSERT(reporter, empty.uniqueID() != emptyClone->uniqueID());
1405    }
1406}
1407
1408DEF_TEST(Picture, reporter) {
1409#ifdef SK_DEBUG
1410    test_deleting_empty_playback();
1411    test_serializing_empty_picture();
1412#else
1413    test_bad_bitmap();
1414#endif
1415    test_unbalanced_save_restores(reporter);
1416    test_peephole();
1417#if SK_SUPPORT_GPU
1418    test_gpu_veto(reporter);
1419#endif
1420    test_gatherpixelrefs(reporter);
1421    test_gatherpixelrefsandrects(reporter);
1422    test_bitmap_with_encoded_data(reporter);
1423    test_clone_empty(reporter);
1424    test_draw_empty(reporter);
1425    test_clip_bound_opt(reporter);
1426    test_clip_expansion(reporter);
1427    test_hierarchical(reporter);
1428    test_gen_id(reporter);
1429}
1430
1431#if SK_SUPPORT_GPU
1432DEF_GPUTEST(GPUPicture, reporter, factory) {
1433    test_gpu_picture_optimization(reporter, factory);
1434}
1435#endif
1436
1437static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
1438    const SkPaint paint;
1439    const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
1440    const SkIRect irect =  { 2, 2, 3, 3 };
1441
1442    // Don't care what these record, as long as they're legal.
1443    canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
1444    canvas->drawBitmapRectToRect(bitmap, &rect, rect, &paint, SkCanvas::kNone_DrawBitmapRectFlag);
1445    canvas->drawBitmapMatrix(bitmap, SkMatrix::I(), &paint);
1446    canvas->drawBitmapNine(bitmap, irect, rect, &paint);
1447    canvas->drawSprite(bitmap, 1, 1);
1448}
1449
1450static void test_draw_bitmaps(SkCanvas* canvas) {
1451    SkBitmap empty;
1452    draw_bitmaps(empty, canvas);
1453    empty.setConfig(SkImageInfo::MakeN32Premul(10, 10));
1454    draw_bitmaps(empty, canvas);
1455}
1456
1457DEF_TEST(Picture_EmptyBitmap, r) {
1458    SkPictureRecorder recorder;
1459    test_draw_bitmaps(recorder.beginRecording(10, 10, NULL, 0));
1460    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1461}
1462
1463DEF_TEST(Canvas_EmptyBitmap, r) {
1464    SkBitmap dst;
1465    dst.allocN32Pixels(10, 10);
1466    SkCanvas canvas(dst);
1467
1468    test_draw_bitmaps(&canvas);
1469}
1470