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