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