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