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 "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 
     38 static 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.
     49 static 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.
     60 static 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 
     69 static 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 
     89 static 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  */
     99 class SaveCountingCanvas : public SkCanvas {
    100 public:
    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 
    127 private:
    128     unsigned int fSaveCount;
    129     unsigned int fSaveLayerCount;
    130     unsigned int fRestoreCount;
    131 
    132     typedef SkCanvas INHERITED;
    133 };
    134 
    135 void 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.
    152 class SkPictureRecorderReplayTester {
    153 public:
    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 
    165 static 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.
    179 static 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
    201 DEF_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 
    245 static 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 
    306 static 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.
    342 static 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 
    357 static 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 
    439 static 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  */
    470 class ClipCountingCanvas : public SkCanvas {
    471 public:
    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 
    499 private:
    500     unsigned fClipCount;
    501 
    502     typedef SkCanvas INHERITED;
    503 };
    504 
    505 static 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 
    525 static 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 
    544 static 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 
    555 DEF_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 
    571 static 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 
    588 static 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 
    595 DEF_TEST(Picture_EmptyBitmap, r) {
    596     SkPictureRecorder recorder;
    597     test_draw_bitmaps(recorder.beginRecording(10, 10));
    598     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
    599 }
    600 
    601 DEF_TEST(Canvas_EmptyBitmap, r) {
    602     SkBitmap dst;
    603     dst.allocN32Pixels(10, 10);
    604     SkCanvas canvas(dst);
    605 
    606     test_draw_bitmaps(&canvas);
    607 }
    608 
    609 DEF_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 
    657 struct 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 
    672 class SpoonFedBBHFactory : public SkBBHFactory {
    673 public:
    674     explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
    675     SkBBoxHierarchy* operator()(const SkRect&) const override {
    676         return SkRef(fBBH);
    677     }
    678 private:
    679     SkBBoxHierarchy* fBBH;
    680 };
    681 
    682 // When the canvas clip covers the full picture, we don't need to call the BBH.
    683 DEF_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 
    704 DEF_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.
    738 DEF_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 
    749 DEF_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 
    759 DEF_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.
    783 DEF_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 }
    798 DEF_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 
    816 DEF_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 
    838 DEF_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 
    857 DEF_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