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