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 "SkBigPicture.h"
9#include "SkBBoxHierarchy.h"
10#include "SkBlurImageFilter.h"
11#include "SkCanvas.h"
12#include "SkColorMatrixFilter.h"
13#include "SkColorPriv.h"
14#include "SkDashPathEffect.h"
15#include "SkData.h"
16#include "SkImageGenerator.h"
17#include "SkImageEncoder.h"
18#include "SkImageGenerator.h"
19#include "SkMD5.h"
20#include "SkMiniRecorder.h"
21#include "SkPaint.h"
22#include "SkPicture.h"
23#include "SkPictureRecorder.h"
24#include "SkPixelRef.h"
25#include "SkRectPriv.h"
26#include "SkRRect.h"
27#include "SkRandom.h"
28#include "SkRecord.h"
29#include "SkShader.h"
30#include "SkStream.h"
31#include "sk_tool_utils.h"
32
33#include "Test.h"
34
35#include "SkLumaColorFilter.h"
36#include "SkColorFilterImageFilter.h"
37
38static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
39    bm->allocN32Pixels(w, h);
40    bm->eraseColor(color);
41    if (immutable) {
42        bm->setImmutable();
43    }
44}
45
46#ifdef SK_DEBUG
47// Ensure that deleting an empty SkPicture does not assert. Asserts only fire
48// in debug mode, so only run in debug mode.
49static void test_deleting_empty_picture() {
50    SkPictureRecorder recorder;
51    // Creates an SkPictureRecord
52    recorder.beginRecording(0, 0);
53    // Turns that into an SkPicture
54    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
55    // Ceates a new SkPictureRecord
56    recorder.beginRecording(0, 0);
57}
58
59// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
60static void test_serializing_empty_picture() {
61    SkPictureRecorder recorder;
62    recorder.beginRecording(0, 0);
63    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
64    SkDynamicMemoryWStream stream;
65    picture->serialize(&stream);
66}
67#endif
68
69static void rand_op(SkCanvas* canvas, SkRandom& rand) {
70    SkPaint paint;
71    SkRect rect = SkRect::MakeWH(50, 50);
72
73    SkScalar unit = rand.nextUScalar1();
74    if (unit <= 0.3) {
75//        SkDebugf("save\n");
76        canvas->save();
77    } else if (unit <= 0.6) {
78//        SkDebugf("restore\n");
79        canvas->restore();
80    } else if (unit <= 0.9) {
81//        SkDebugf("clip\n");
82        canvas->clipRect(rect);
83    } else {
84//        SkDebugf("draw\n");
85        canvas->drawPaint(paint);
86    }
87}
88
89static void set_canvas_to_save_count_4(SkCanvas* canvas) {
90    canvas->restoreToCount(1);
91    canvas->save();
92    canvas->save();
93    canvas->save();
94}
95
96/**
97 * A canvas that records the number of saves, saveLayers and restores.
98 */
99class SaveCountingCanvas : public SkCanvas {
100public:
101    SaveCountingCanvas(int width, int height)
102        : INHERITED(width, height)
103        , fSaveCount(0)
104        , fSaveLayerCount(0)
105        , fRestoreCount(0){
106    }
107
108    SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
109        ++fSaveLayerCount;
110        return this->INHERITED::getSaveLayerStrategy(rec);
111    }
112
113    void willSave() override {
114        ++fSaveCount;
115        this->INHERITED::willSave();
116    }
117
118    void willRestore() override {
119        ++fRestoreCount;
120        this->INHERITED::willRestore();
121    }
122
123    unsigned int getSaveCount() const { return fSaveCount; }
124    unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
125    unsigned int getRestoreCount() const { return fRestoreCount; }
126
127private:
128    unsigned int fSaveCount;
129    unsigned int fSaveLayerCount;
130    unsigned int fRestoreCount;
131
132    typedef SkCanvas INHERITED;
133};
134
135void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
136                      unsigned int numSaves, unsigned int numSaveLayers,
137                      unsigned int numRestores) {
138    SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
139                              SkScalarCeilToInt(picture->cullRect().height()));
140
141    picture->playback(&canvas);
142
143    // Optimizations may have removed these,
144    // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
145    REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
146    REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
147    REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
148}
149
150// This class exists so SkPicture can friend it and give it access to
151// the 'partialReplay' method.
152class SkPictureRecorderReplayTester {
153public:
154    static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) {
155        SkPictureRecorder recorder2;
156
157        SkCanvas* canvas = recorder2.beginRecording(10, 10);
158
159        recorder->partialReplay(canvas);
160
161        return recorder2.finishRecordingAsPicture();
162    }
163};
164
165static void create_imbalance(SkCanvas* canvas) {
166    SkRect clipRect = SkRect::MakeWH(2, 2);
167    SkRect drawRect = SkRect::MakeWH(10, 10);
168    canvas->save();
169        canvas->clipRect(clipRect, kReplace_SkClipOp);
170        canvas->translate(1.0f, 1.0f);
171        SkPaint p;
172        p.setColor(SK_ColorGREEN);
173        canvas->drawRect(drawRect, p);
174    // no restore
175}
176
177// This tests that replaying a potentially unbalanced picture into a canvas
178// doesn't affect the canvas' save count or matrix/clip state.
179static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
180    SkBitmap bm;
181    bm.allocN32Pixels(4, 3);
182    SkCanvas canvas(bm);
183
184    int beforeSaveCount = canvas.getSaveCount();
185
186    SkMatrix beforeMatrix = canvas.getTotalMatrix();
187
188    SkRect beforeClip = canvas.getLocalClipBounds();
189
190    canvas.drawPicture(picture);
191
192    REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
193    REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
194
195    SkRect afterClip = canvas.getLocalClipBounds();
196
197    REPORTER_ASSERT(reporter, afterClip == beforeClip);
198}
199
200// Test out SkPictureRecorder::partialReplay
201DEF_TEST(PictureRecorder_replay, reporter) {
202    // check save/saveLayer state
203    {
204        SkPictureRecorder recorder;
205
206        SkCanvas* canvas = recorder.beginRecording(10, 10);
207
208        canvas->saveLayer(nullptr, nullptr);
209
210        sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
211
212        // The extra save and restore comes from the Copy process.
213        check_save_state(reporter, copy.get(), 2, 1, 3);
214
215        canvas->saveLayer(nullptr, nullptr);
216
217        sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
218
219        check_save_state(reporter, final.get(), 1, 2, 3);
220
221        // The copy shouldn't pick up any operations added after it was made
222        check_save_state(reporter, copy.get(), 2, 1, 3);
223    }
224
225    // Recreate the Android partialReplay test case
226    {
227        SkPictureRecorder recorder;
228
229        SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
230        create_imbalance(canvas);
231
232        int expectedSaveCount = canvas->getSaveCount();
233
234        sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
235        check_balance(reporter, copy.get());
236
237        REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
238
239        // End the recording of source to test the picture finalization
240        // process isn't complicated by the partialReplay step
241        sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
242    }
243}
244
245static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
246    SkCanvas testCanvas(100, 100);
247    set_canvas_to_save_count_4(&testCanvas);
248
249    REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
250
251    SkPaint paint;
252    SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
253
254    SkPictureRecorder recorder;
255
256    {
257        // Create picture with 2 unbalanced saves
258        SkCanvas* canvas = recorder.beginRecording(100, 100);
259        canvas->save();
260        canvas->translate(10, 10);
261        canvas->drawRect(rect, paint);
262        canvas->save();
263        canvas->translate(10, 10);
264        canvas->drawRect(rect, paint);
265        sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture());
266
267        testCanvas.drawPicture(extraSavePicture);
268        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
269    }
270
271    set_canvas_to_save_count_4(&testCanvas);
272
273    {
274        // Create picture with 2 unbalanced restores
275        SkCanvas* canvas = recorder.beginRecording(100, 100);
276        canvas->save();
277        canvas->translate(10, 10);
278        canvas->drawRect(rect, paint);
279        canvas->save();
280        canvas->translate(10, 10);
281        canvas->drawRect(rect, paint);
282        canvas->restore();
283        canvas->restore();
284        canvas->restore();
285        canvas->restore();
286        sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture());
287
288        testCanvas.drawPicture(extraRestorePicture);
289        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
290    }
291
292    set_canvas_to_save_count_4(&testCanvas);
293
294    {
295        SkCanvas* canvas = recorder.beginRecording(100, 100);
296        canvas->translate(10, 10);
297        canvas->drawRect(rect, paint);
298        sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture());
299
300        testCanvas.drawPicture(noSavePicture);
301        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
302        REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
303    }
304}
305
306static void test_peephole() {
307    SkRandom rand;
308
309    SkPictureRecorder recorder;
310
311    for (int j = 0; j < 100; j++) {
312        SkRandom rand2(rand); // remember the seed
313
314        SkCanvas* canvas = recorder.beginRecording(100, 100);
315
316        for (int i = 0; i < 1000; ++i) {
317            rand_op(canvas, rand);
318        }
319        sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
320
321        rand = rand2;
322    }
323
324    {
325        SkCanvas* canvas = recorder.beginRecording(100, 100);
326        SkRect rect = SkRect::MakeWH(50, 50);
327
328        for (int i = 0; i < 100; ++i) {
329            canvas->save();
330        }
331        while (canvas->getSaveCount() > 1) {
332            canvas->clipRect(rect);
333            canvas->restore();
334        }
335        sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
336    }
337}
338
339#ifndef SK_DEBUG
340// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
341// should never do this.
342static void test_bad_bitmap() {
343    // This bitmap has a width and height but no pixels. As a result, attempting to record it will
344    // fail.
345    SkBitmap bm;
346    bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
347    SkPictureRecorder recorder;
348    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
349    recordingCanvas->drawBitmap(bm, 0, 0);
350    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
351
352    SkCanvas canvas;
353    canvas.drawPicture(picture);
354}
355#endif
356
357static void test_clip_bound_opt(skiatest::Reporter* reporter) {
358    // Test for crbug.com/229011
359    SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
360                                    SkIntToScalar(2), SkIntToScalar(2));
361    SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
362                                    SkIntToScalar(1), SkIntToScalar(1));
363    SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
364                                    SkIntToScalar(1), SkIntToScalar(1));
365
366    SkPath invPath;
367    invPath.addOval(rect1);
368    invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
369    SkPath path;
370    path.addOval(rect2);
371    SkPath path2;
372    path2.addOval(rect3);
373    SkIRect clipBounds;
374    SkPictureRecorder recorder;
375
376    // Testing conservative-raster-clip that is enabled by PictureRecord
377    {
378        SkCanvas* canvas = recorder.beginRecording(10, 10);
379        canvas->clipPath(invPath);
380        clipBounds = canvas->getDeviceClipBounds();
381        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
382        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
383        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
384        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
385    }
386    {
387        SkCanvas* canvas = recorder.beginRecording(10, 10);
388        canvas->clipPath(path);
389        canvas->clipPath(invPath);
390        clipBounds = canvas->getDeviceClipBounds();
391        REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
392        REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
393        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
394        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
395    }
396    {
397        SkCanvas* canvas = recorder.beginRecording(10, 10);
398        canvas->clipPath(path);
399        canvas->clipPath(invPath, kUnion_SkClipOp);
400        clipBounds = canvas->getDeviceClipBounds();
401        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
402        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
403        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
404        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
405    }
406    {
407        SkCanvas* canvas = recorder.beginRecording(10, 10);
408        canvas->clipPath(path, kDifference_SkClipOp);
409        clipBounds = canvas->getDeviceClipBounds();
410        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
411        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
412        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
413        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
414    }
415    {
416        SkCanvas* canvas = recorder.beginRecording(10, 10);
417        canvas->clipPath(path, kReverseDifference_SkClipOp);
418        clipBounds = canvas->getDeviceClipBounds();
419        // True clip is actually empty in this case, but the best
420        // determination we can make using only bounds as input is that the
421        // clip is included in the bounds of 'path'.
422        REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
423        REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
424        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
425        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
426    }
427    {
428        SkCanvas* canvas = recorder.beginRecording(10, 10);
429        canvas->clipPath(path, kIntersect_SkClipOp);
430        canvas->clipPath(path2, kXOR_SkClipOp);
431        clipBounds = canvas->getDeviceClipBounds();
432        REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
433        REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
434        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
435        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
436    }
437}
438
439static void test_cull_rect_reset(skiatest::Reporter* reporter) {
440    SkPictureRecorder recorder;
441    SkRect bounds = SkRect::MakeWH(10, 10);
442    SkRTreeFactory factory;
443    SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
444    bounds = SkRect::MakeWH(100, 100);
445    SkPaint paint;
446    canvas->drawRect(bounds, paint);
447    canvas->drawRect(bounds, paint);
448    sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds));
449    const SkBigPicture* picture = p->asSkBigPicture();
450    REPORTER_ASSERT(reporter, picture);
451
452    SkRect finalCullRect = picture->cullRect();
453    REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
454    REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
455    REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
456    REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
457
458    const SkBBoxHierarchy* pictureBBH = picture->bbh();
459    SkRect bbhCullRect = pictureBBH->getRootBound();
460    REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
461    REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
462    REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
463    REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
464}
465
466
467/**
468 * A canvas that records the number of clip commands.
469 */
470class ClipCountingCanvas : public SkCanvas {
471public:
472    ClipCountingCanvas(int width, int height)
473        : INHERITED(width, height)
474        , fClipCount(0){
475    }
476
477    void onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) override {
478        fClipCount += 1;
479        this->INHERITED::onClipRect(r, op, edgeStyle);
480    }
481
482    void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle)override {
483        fClipCount += 1;
484        this->INHERITED::onClipRRect(rrect, op, edgeStyle);
485    }
486
487    void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) override {
488        fClipCount += 1;
489        this->INHERITED::onClipPath(path, op, edgeStyle);
490    }
491
492    void onClipRegion(const SkRegion& deviceRgn, SkClipOp op) override {
493        fClipCount += 1;
494        this->INHERITED::onClipRegion(deviceRgn, op);
495    }
496
497    unsigned getClipCount() const { return fClipCount; }
498
499private:
500    unsigned fClipCount;
501
502    typedef SkCanvas INHERITED;
503};
504
505static void test_clip_expansion(skiatest::Reporter* reporter) {
506    SkPictureRecorder recorder;
507    SkCanvas* canvas = recorder.beginRecording(10, 10);
508
509    canvas->clipRect(SkRect::MakeEmpty(), kReplace_SkClipOp);
510    // The following expanding clip should not be skipped.
511    canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), kUnion_SkClipOp);
512    // Draw something so the optimizer doesn't just fold the world.
513    SkPaint p;
514    p.setColor(SK_ColorBLUE);
515    canvas->drawPaint(p);
516    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
517
518    ClipCountingCanvas testCanvas(10, 10);
519    picture->playback(&testCanvas);
520
521    // Both clips should be present on playback.
522    REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
523}
524
525static void test_gen_id(skiatest::Reporter* reporter) {
526
527    SkPictureRecorder recorder;
528    recorder.beginRecording(0, 0);
529    sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture());
530
531    // Empty pictures should still have a valid ID
532    REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
533
534    SkCanvas* canvas = recorder.beginRecording(1, 1);
535    canvas->drawColor(SK_ColorWHITE);
536    sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture());
537    // picture should have a non-zero id after recording
538    REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
539
540    // both pictures should have different ids
541    REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
542}
543
544static void test_typeface(skiatest::Reporter* reporter) {
545    SkPictureRecorder recorder;
546    SkCanvas* canvas = recorder.beginRecording(10, 10);
547    SkPaint paint;
548    paint.setTypeface(SkTypeface::MakeFromName("Arial", SkFontStyle::Italic()));
549    canvas->drawString("Q", 0, 10, paint);
550    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
551    SkDynamicMemoryWStream stream;
552    picture->serialize(&stream);
553}
554
555DEF_TEST(Picture, reporter) {
556    test_typeface(reporter);
557#ifdef SK_DEBUG
558    test_deleting_empty_picture();
559    test_serializing_empty_picture();
560#else
561    test_bad_bitmap();
562#endif
563    test_unbalanced_save_restores(reporter);
564    test_peephole();
565    test_clip_bound_opt(reporter);
566    test_clip_expansion(reporter);
567    test_gen_id(reporter);
568    test_cull_rect_reset(reporter);
569}
570
571static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
572    const SkPaint paint;
573    const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
574    const SkIRect irect =  { 2, 2, 3, 3 };
575    int divs[] = { 2, 3 };
576    SkCanvas::Lattice lattice;
577    lattice.fXCount = lattice.fYCount = 2;
578    lattice.fXDivs = lattice.fYDivs = divs;
579
580    // Don't care what these record, as long as they're legal.
581    canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
582    canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
583    canvas->drawBitmapNine(bitmap, irect, rect, &paint);
584    canvas->drawBitmap(bitmap, 1, 1);   // drawSprite
585    canvas->drawBitmapLattice(bitmap, lattice, rect, &paint);
586}
587
588static void test_draw_bitmaps(SkCanvas* canvas) {
589    SkBitmap empty;
590    draw_bitmaps(empty, canvas);
591    empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
592    draw_bitmaps(empty, canvas);
593}
594
595DEF_TEST(Picture_EmptyBitmap, r) {
596    SkPictureRecorder recorder;
597    test_draw_bitmaps(recorder.beginRecording(10, 10));
598    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
599}
600
601DEF_TEST(Canvas_EmptyBitmap, r) {
602    SkBitmap dst;
603    dst.allocN32Pixels(10, 10);
604    SkCanvas canvas(dst);
605
606    test_draw_bitmaps(&canvas);
607}
608
609DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
610    // This test is from crbug.com/344987.
611    // The commands are:
612    //   saveLayer with paint that modifies alpha
613    //     drawBitmapRect
614    //     drawBitmapRect
615    //   restore
616    // The bug was that this structure was modified so that:
617    //  - The saveLayer and restore were eliminated
618    //  - The alpha was only applied to the first drawBitmapRectToRect
619
620    // This test draws blue and red squares inside a 50% transparent
621    // layer.  Both colours should show up muted.
622    // When the bug is present, the red square (the second bitmap)
623    // shows upwith full opacity.
624
625    SkBitmap blueBM;
626    make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
627    SkBitmap redBM;
628    make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
629    SkPaint semiTransparent;
630    semiTransparent.setAlpha(0x80);
631
632    SkPictureRecorder recorder;
633    SkCanvas* canvas = recorder.beginRecording(100, 100);
634    canvas->drawColor(0);
635
636    canvas->saveLayer(nullptr, &semiTransparent);
637    canvas->drawBitmap(blueBM, 25, 25);
638    canvas->drawBitmap(redBM, 50, 50);
639    canvas->restore();
640
641    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
642
643    // Now replay the picture back on another canvas
644    // and check a couple of its pixels.
645    SkBitmap replayBM;
646    make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
647    SkCanvas replayCanvas(replayBM);
648    picture->playback(&replayCanvas);
649    replayCanvas.flush();
650
651    // With the bug present, at (55, 55) we would get a fully opaque red
652    // intead of a dark red.
653    REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
654    REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
655}
656
657struct CountingBBH : public SkBBoxHierarchy {
658    mutable int searchCalls;
659    SkRect rootBound;
660
661    CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
662
663    void search(const SkRect& query, SkTDArray<int>* results) const override {
664        this->searchCalls++;
665    }
666
667    void insert(const SkRect[], int) override {}
668    virtual size_t bytesUsed() const override { return 0; }
669    SkRect getRootBound() const override { return rootBound; }
670};
671
672class SpoonFedBBHFactory : public SkBBHFactory {
673public:
674    explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
675    SkBBoxHierarchy* operator()(const SkRect&) const override {
676        return SkRef(fBBH);
677    }
678private:
679    SkBBoxHierarchy* fBBH;
680};
681
682// When the canvas clip covers the full picture, we don't need to call the BBH.
683DEF_TEST(Picture_SkipBBH, r) {
684    SkRect bound = SkRect::MakeWH(320, 240);
685    CountingBBH bbh(bound);
686    SpoonFedBBHFactory factory(&bbh);
687
688    SkPictureRecorder recorder;
689    SkCanvas* c = recorder.beginRecording(bound, &factory);
690    // Record a few ops so we don't hit a small- or empty- picture optimization.
691        c->drawRect(bound, SkPaint());
692        c->drawRect(bound, SkPaint());
693    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
694
695    SkCanvas big(640, 480), small(300, 200);
696
697    picture->playback(&big);
698    REPORTER_ASSERT(r, bbh.searchCalls == 0);
699
700    picture->playback(&small);
701    REPORTER_ASSERT(r, bbh.searchCalls == 1);
702}
703
704DEF_TEST(Picture_BitmapLeak, r) {
705    SkBitmap mut, immut;
706    mut.allocN32Pixels(300, 200);
707    immut.allocN32Pixels(300, 200);
708    immut.setImmutable();
709    SkASSERT(!mut.isImmutable());
710    SkASSERT(immut.isImmutable());
711
712    // No one can hold a ref on our pixels yet.
713    REPORTER_ASSERT(r, mut.pixelRef()->unique());
714    REPORTER_ASSERT(r, immut.pixelRef()->unique());
715
716    sk_sp<SkPicture> pic;
717    {
718        // we want the recorder to go out of scope before our subsequent checks, so we
719        // place it inside local braces.
720        SkPictureRecorder rec;
721        SkCanvas* canvas = rec.beginRecording(1920, 1200);
722            canvas->drawBitmap(mut, 0, 0);
723            canvas->drawBitmap(immut, 800, 600);
724        pic = rec.finishRecordingAsPicture();
725    }
726
727    // The picture shares the immutable pixels but copies the mutable ones.
728    REPORTER_ASSERT(r, mut.pixelRef()->unique());
729    REPORTER_ASSERT(r, !immut.pixelRef()->unique());
730
731    // When the picture goes away, it's just our bitmaps holding the refs.
732    pic = nullptr;
733    REPORTER_ASSERT(r, mut.pixelRef()->unique());
734    REPORTER_ASSERT(r, immut.pixelRef()->unique());
735}
736
737// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
738DEF_TEST(Picture_getRecordingCanvas, r) {
739    SkPictureRecorder rec;
740    REPORTER_ASSERT(r, !rec.getRecordingCanvas());
741    for (int i = 0; i < 3; i++) {
742        rec.beginRecording(100, 100);
743        REPORTER_ASSERT(r, rec.getRecordingCanvas());
744        rec.finishRecordingAsPicture();
745        REPORTER_ASSERT(r, !rec.getRecordingCanvas());
746    }
747}
748
749DEF_TEST(MiniRecorderLeftHanging, r) {
750    // Any shader or other ref-counted effect will do just fine here.
751    SkPaint paint;
752    paint.setShader(SkShader::MakeColorShader(SK_ColorRED));
753
754    SkMiniRecorder rec;
755    REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
756    // Don't call rec.detachPicture().  Test succeeds by not asserting or leaking the shader.
757}
758
759DEF_TEST(Picture_preserveCullRect, r) {
760    SkPictureRecorder recorder;
761
762    SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
763    c->clear(SK_ColorCYAN);
764
765    sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
766    SkDynamicMemoryWStream wstream;
767    picture->serialize(&wstream);
768
769    std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
770    sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream.get()));
771
772    REPORTER_ASSERT(r, deserializedPicture != nullptr);
773    REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
774    REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
775    REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
776    REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
777}
778
779
780// If we record bounded ops into a picture with a big cull and calculate the
781// bounds of those ops, we should trim down the picture cull to the ops' bounds.
782// If we're not using an SkBBH, we shouldn't change it.
783DEF_TEST(Picture_UpdatedCull_1, r) {
784    // Testing 1 draw exercises SkMiniPicture.
785    SkRTreeFactory factory;
786    SkPictureRecorder recorder;
787
788    auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory);
789    canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
790    auto pic = recorder.finishRecordingAsPicture();
791    REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,20));
792
793    canvas = recorder.beginRecording(SkRectPriv::MakeLargest());
794    canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
795    pic = recorder.finishRecordingAsPicture();
796    REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest());
797}
798DEF_TEST(Picture_UpdatedCull_2, r) {
799    // Testing >1 draw exercises SkBigPicture.
800    SkRTreeFactory factory;
801    SkPictureRecorder recorder;
802
803    auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory);
804    canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
805    canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
806    auto pic = recorder.finishRecordingAsPicture();
807    REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,40));
808
809    canvas = recorder.beginRecording(SkRectPriv::MakeLargest());
810    canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
811    canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
812    pic = recorder.finishRecordingAsPicture();
813    REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest());
814}
815
816DEF_TEST(Picture_RecordsFlush, r) {
817    SkPictureRecorder recorder;
818
819    auto canvas = recorder.beginRecording(SkRect::MakeWH(100,100));
820    for (int i = 0; i < 10; i++) {
821        canvas->clear(0);
822        for (int j = 0; j < 10; j++) {
823            canvas->drawRect(SkRect::MakeXYWH(i*10,j*10,10,10), SkPaint());
824        }
825        canvas->flush();
826    }
827
828    // Did we record the flushes?
829    auto pic = recorder.finishRecordingAsPicture();
830    REPORTER_ASSERT(r, pic->approximateOpCount() == 120);  // 10 clears, 100 draws, 10 flushes
831
832    // Do we serialize and deserialize flushes?
833    auto skp = pic->serialize();
834    auto back = SkPicture::MakeFromData(skp->data(), skp->size());
835    REPORTER_ASSERT(r, back->approximateOpCount() == pic->approximateOpCount());
836}
837
838DEF_TEST(Placeholder, r) {
839    SkRect cull = { 0,0, 10,20 };
840
841    // Each placeholder is unique.
842    sk_sp<SkPicture> p1 = SkPicture::MakePlaceholder(cull),
843                     p2 = SkPicture::MakePlaceholder(cull);
844    REPORTER_ASSERT(r, p1->cullRect() == p2->cullRect());
845    REPORTER_ASSERT(r, p1->cullRect() == cull);
846    REPORTER_ASSERT(r, p1->uniqueID() != p2->uniqueID());
847
848    // Placeholders are never unrolled by SkCanvas (while other small pictures may be).
849    SkPictureRecorder recorder;
850    SkCanvas* canvas = recorder.beginRecording(cull);
851        canvas->drawPicture(p1);
852        canvas->drawPicture(p2);
853    sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
854    REPORTER_ASSERT(r, pic->approximateOpCount() == 2);
855}
856
857DEF_TEST(Picture_empty_serial, reporter) {
858    SkPictureRecorder rec;
859    (void)rec.beginRecording(10, 10);
860    auto pic = rec.finishRecordingAsPicture();
861    REPORTER_ASSERT(reporter, pic);
862
863    auto data = pic->serialize();
864    REPORTER_ASSERT(reporter, data);
865
866    auto pic2 = SkPicture::MakeFromData(data->data(), data->size());
867    REPORTER_ASSERT(reporter, pic2);
868}
869
870