PictureTest.cpp revision 290f00cd752b51f517b88c40bc89016fcaf5e477
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 "SkPaint.h"
21#include "SkPicture.h"
22#include "SkPictureRecorder.h"
23#include "SkPictureUtils.h"
24#include "SkPixelRef.h"
25#include "SkPixelSerializer.h"
26#include "SkMiniRecorder.h"
27#include "SkRRect.h"
28#include "SkRandom.h"
29#include "SkRecord.h"
30#include "SkShader.h"
31#include "SkStream.h"
32#include "sk_tool_utils.h"
33
34#include "Test.h"
35
36#include "SkLumaColorFilter.h"
37#include "SkColorFilterImageFilter.h"
38
39static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
40    bm->allocN32Pixels(w, h);
41    bm->eraseColor(color);
42    if (immutable) {
43        bm->setImmutable();
44    }
45}
46
47// For a while willPlayBackBitmaps() ignored SkImages and just looked for SkBitmaps.
48static void test_images_are_found_by_willPlayBackBitmaps(skiatest::Reporter* reporter) {
49    // We just need _some_ SkImage.
50    SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(SkBitmap()));
51
52    SkPictureRecorder recorder;
53    {
54        auto canvas = recorder.beginRecording(100,100);
55        canvas->drawImage(image, 0,0);
56    }
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. */
63static void test_analysis(skiatest::Reporter* reporter) {
64    SkPictureRecorder recorder;
65
66    SkCanvas* canvas = recorder.beginRecording(100, 100);
67    {
68        canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ());
69    }
70    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.
97static 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.
108static 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
117static 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
139static 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<SkDashPathEffect> 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
277static 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
480static 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
543static 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 */
553class SaveCountingCanvas : public SkCanvas {
554public:
555    SaveCountingCanvas(int width, int height)
556        : INHERITED(width, height)
557        , fSaveCount(0)
558        , fSaveLayerCount(0)
559        , fRestoreCount(0){
560    }
561
562    virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint,
563                                            SaveFlags flags) override {
564        ++fSaveLayerCount;
565        return this->INHERITED::willSaveLayer(bounds, paint, flags);
566    }
567
568    void willSave() override {
569        ++fSaveCount;
570        this->INHERITED::willSave();
571    }
572
573    void willRestore() override {
574        ++fRestoreCount;
575        this->INHERITED::willRestore();
576    }
577
578    unsigned int getSaveCount() const { return fSaveCount; }
579    unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
580    unsigned int getRestoreCount() const { return fRestoreCount; }
581
582private:
583    unsigned int fSaveCount;
584    unsigned int fSaveLayerCount;
585    unsigned int fRestoreCount;
586
587    typedef SkCanvas INHERITED;
588};
589
590void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
591                      unsigned int numSaves, unsigned int numSaveLayers,
592                      unsigned int numRestores) {
593    SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
594                              SkScalarCeilToInt(picture->cullRect().height()));
595
596    picture->playback(&canvas);
597
598    // Optimizations may have removed these,
599    // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
600    REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
601    REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
602    REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
603}
604
605// This class exists so SkPicture can friend it and give it access to
606// the 'partialReplay' method.
607class SkPictureRecorderReplayTester {
608public:
609    static SkPicture* Copy(SkPictureRecorder* recorder) {
610        SkPictureRecorder recorder2;
611
612        SkCanvas* canvas = recorder2.beginRecording(10, 10);
613
614        recorder->partialReplay(canvas);
615
616        return recorder2.endRecording();
617    }
618};
619
620static void create_imbalance(SkCanvas* canvas) {
621    SkRect clipRect = SkRect::MakeWH(2, 2);
622    SkRect drawRect = SkRect::MakeWH(10, 10);
623    canvas->save();
624        canvas->clipRect(clipRect, SkRegion::kReplace_Op);
625        canvas->translate(1.0f, 1.0f);
626        SkPaint p;
627        p.setColor(SK_ColorGREEN);
628        canvas->drawRect(drawRect, p);
629    // no restore
630}
631
632// This tests that replaying a potentially unbalanced picture into a canvas
633// doesn't affect the canvas' save count or matrix/clip state.
634static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
635    SkBitmap bm;
636    bm.allocN32Pixels(4, 3);
637    SkCanvas canvas(bm);
638
639    int beforeSaveCount = canvas.getSaveCount();
640
641    SkMatrix beforeMatrix = canvas.getTotalMatrix();
642
643    SkRect beforeClip;
644
645    canvas.getClipBounds(&beforeClip);
646
647    canvas.drawPicture(picture);
648
649    REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
650    REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
651
652    SkRect afterClip;
653
654    canvas.getClipBounds(&afterClip);
655
656    REPORTER_ASSERT(reporter, afterClip == beforeClip);
657}
658
659// Test out SkPictureRecorder::partialReplay
660DEF_TEST(PictureRecorder_replay, reporter) {
661    // check save/saveLayer state
662    {
663        SkPictureRecorder recorder;
664
665        SkCanvas* canvas = recorder.beginRecording(10, 10);
666
667        canvas->saveLayer(nullptr, nullptr);
668
669        SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
670
671        // The extra save and restore comes from the Copy process.
672        check_save_state(reporter, copy, 2, 1, 3);
673
674        canvas->saveLayer(nullptr, nullptr);
675
676        SkAutoTUnref<SkPicture> final(recorder.endRecording());
677
678        check_save_state(reporter, final, 1, 2, 3);
679
680        // The copy shouldn't pick up any operations added after it was made
681        check_save_state(reporter, copy, 2, 1, 3);
682    }
683
684    // (partially) check leakage of draw ops
685    {
686        SkPictureRecorder recorder;
687
688        SkCanvas* canvas = recorder.beginRecording(10, 10);
689
690        SkRect r = SkRect::MakeWH(5, 5);
691        SkPaint p;
692
693        canvas->drawRect(r, p);
694
695        SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
696
697        REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
698
699        SkBitmap bm;
700        make_bm(&bm, 10, 10, SK_ColorRED, true);
701
702        r.offset(5.0f, 5.0f);
703        canvas->drawBitmapRect(bm, r, nullptr);
704
705        SkAutoTUnref<SkPicture> final(recorder.endRecording());
706        REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
707
708        REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
709
710        // The snapshot shouldn't pick up any operations added after it was made
711        REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
712    }
713
714    // Recreate the Android partialReplay test case
715    {
716        SkPictureRecorder recorder;
717
718        SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
719        create_imbalance(canvas);
720
721        int expectedSaveCount = canvas->getSaveCount();
722
723        SkAutoTUnref<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
724        check_balance(reporter, copy);
725
726        REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
727
728        // End the recording of source to test the picture finalization
729        // process isn't complicated by the partialReplay step
730        SkAutoTUnref<SkPicture> final(recorder.endRecording());
731    }
732}
733
734static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
735    SkCanvas testCanvas(100, 100);
736    set_canvas_to_save_count_4(&testCanvas);
737
738    REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
739
740    SkPaint paint;
741    SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
742
743    SkPictureRecorder recorder;
744
745    {
746        // Create picture with 2 unbalanced saves
747        SkCanvas* canvas = recorder.beginRecording(100, 100);
748        canvas->save();
749        canvas->translate(10, 10);
750        canvas->drawRect(rect, paint);
751        canvas->save();
752        canvas->translate(10, 10);
753        canvas->drawRect(rect, paint);
754        SkAutoTUnref<SkPicture> extraSavePicture(recorder.endRecording());
755
756        testCanvas.drawPicture(extraSavePicture);
757        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
758    }
759
760    set_canvas_to_save_count_4(&testCanvas);
761
762    {
763        // Create picture with 2 unbalanced restores
764        SkCanvas* canvas = recorder.beginRecording(100, 100);
765        canvas->save();
766        canvas->translate(10, 10);
767        canvas->drawRect(rect, paint);
768        canvas->save();
769        canvas->translate(10, 10);
770        canvas->drawRect(rect, paint);
771        canvas->restore();
772        canvas->restore();
773        canvas->restore();
774        canvas->restore();
775        SkAutoTUnref<SkPicture> extraRestorePicture(recorder.endRecording());
776
777        testCanvas.drawPicture(extraRestorePicture);
778        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
779    }
780
781    set_canvas_to_save_count_4(&testCanvas);
782
783    {
784        SkCanvas* canvas = recorder.beginRecording(100, 100);
785        canvas->translate(10, 10);
786        canvas->drawRect(rect, paint);
787        SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording());
788
789        testCanvas.drawPicture(noSavePicture);
790        REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
791        REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
792    }
793}
794
795static void test_peephole() {
796    SkRandom rand;
797
798    SkPictureRecorder recorder;
799
800    for (int j = 0; j < 100; j++) {
801        SkRandom rand2(rand); // remember the seed
802
803        SkCanvas* canvas = recorder.beginRecording(100, 100);
804
805        for (int i = 0; i < 1000; ++i) {
806            rand_op(canvas, rand);
807        }
808        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
809
810        rand = rand2;
811    }
812
813    {
814        SkCanvas* canvas = recorder.beginRecording(100, 100);
815        SkRect rect = SkRect::MakeWH(50, 50);
816
817        for (int i = 0; i < 100; ++i) {
818            canvas->save();
819        }
820        while (canvas->getSaveCount() > 1) {
821            canvas->clipRect(rect);
822            canvas->restore();
823        }
824        SkAutoTUnref<SkPicture> picture(recorder.endRecording());
825    }
826}
827
828#ifndef SK_DEBUG
829// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
830// should never do this.
831static void test_bad_bitmap() {
832    // This bitmap has a width and height but no pixels. As a result, attempting to record it will
833    // fail.
834    SkBitmap bm;
835    bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
836    SkPictureRecorder recorder;
837    SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
838    recordingCanvas->drawBitmap(bm, 0, 0);
839    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
840
841    SkCanvas canvas;
842    canvas.drawPicture(picture);
843}
844#endif
845
846static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
847    SkPictureRecorder recorder;
848    SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bitmap.width()),
849                                               SkIntToScalar(bitmap.height()));
850    canvas->drawBitmap(bitmap, 0, 0);
851    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
852
853    SkDynamicMemoryWStream wStream;
854    sk_tool_utils::PngPixelSerializer serializer;
855    picture->serialize(&wStream, &serializer);
856    return wStream.copyToData();
857}
858
859struct ErrorContext {
860    int fErrors;
861    skiatest::Reporter* fReporter;
862};
863
864static 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
875static void test_bitmap_with_encoded_data(skiatest::Reporter* reporter) {
876    // Create a bitmap that will be encoded.
877    SkBitmap original;
878    make_bm(&original, 100, 100, SK_ColorBLUE, true);
879    SkDynamicMemoryWStream wStream;
880    if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
881        return;
882    }
883    SkAutoDataUnref data(wStream.copyToData());
884
885    SkBitmap bm;
886    bool installSuccess = SkDEPRECATED_InstallDiscardablePixelRef(data, &bm);
887    REPORTER_ASSERT(reporter, installSuccess);
888
889    // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
890    // Flattening original will follow the old path of performing an encode, while flattening bm
891    // will use the already encoded data.
892    SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
893    SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
894    REPORTER_ASSERT(reporter, picture1->equals(picture2));
895    // Now test that a parse error was generated when trying to create a new SkPicture without
896    // providing a function to decode the bitmap.
897    ErrorContext context;
898    context.fErrors = 0;
899    context.fReporter = reporter;
900    SkSetErrorCallback(assert_one_parse_error_cb, &context);
901    SkMemoryStream pictureStream(picture1);
902    SkClearLastError();
903    SkAutoTUnref<SkPicture> pictureFromStream(SkPicture::CreateFromStream(&pictureStream, nullptr));
904    REPORTER_ASSERT(reporter, pictureFromStream.get() != nullptr);
905    SkClearLastError();
906    SkSetErrorCallback(nullptr, nullptr);
907}
908
909static void test_clip_bound_opt(skiatest::Reporter* reporter) {
910    // Test for crbug.com/229011
911    SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
912                                    SkIntToScalar(2), SkIntToScalar(2));
913    SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
914                                    SkIntToScalar(1), SkIntToScalar(1));
915    SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
916                                    SkIntToScalar(1), SkIntToScalar(1));
917
918    SkPath invPath;
919    invPath.addOval(rect1);
920    invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
921    SkPath path;
922    path.addOval(rect2);
923    SkPath path2;
924    path2.addOval(rect3);
925    SkIRect clipBounds;
926    SkPictureRecorder recorder;
927
928    // Testing conservative-raster-clip that is enabled by PictureRecord
929    {
930        SkCanvas* canvas = recorder.beginRecording(10, 10);
931        canvas->clipPath(invPath, SkRegion::kIntersect_Op);
932        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
933        REPORTER_ASSERT(reporter, true == nonEmpty);
934        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
935        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
936        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
937        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
938    }
939    {
940        SkCanvas* canvas = recorder.beginRecording(10, 10);
941        canvas->clipPath(path, SkRegion::kIntersect_Op);
942        canvas->clipPath(invPath, SkRegion::kIntersect_Op);
943        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
944        REPORTER_ASSERT(reporter, true == nonEmpty);
945        REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
946        REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
947        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
948        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
949    }
950    {
951        SkCanvas* canvas = recorder.beginRecording(10, 10);
952        canvas->clipPath(path, SkRegion::kIntersect_Op);
953        canvas->clipPath(invPath, SkRegion::kUnion_Op);
954        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
955        REPORTER_ASSERT(reporter, true == nonEmpty);
956        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
957        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
958        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
959        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
960    }
961    {
962        SkCanvas* canvas = recorder.beginRecording(10, 10);
963        canvas->clipPath(path, SkRegion::kDifference_Op);
964        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
965        REPORTER_ASSERT(reporter, true == nonEmpty);
966        REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
967        REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
968        REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
969        REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
970    }
971    {
972        SkCanvas* canvas = recorder.beginRecording(10, 10);
973        canvas->clipPath(path, SkRegion::kReverseDifference_Op);
974        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
975        // True clip is actually empty in this case, but the best
976        // determination we can make using only bounds as input is that the
977        // clip is included in the bounds of 'path'.
978        REPORTER_ASSERT(reporter, true == nonEmpty);
979        REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
980        REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
981        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
982        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
983    }
984    {
985        SkCanvas* canvas = recorder.beginRecording(10, 10);
986        canvas->clipPath(path, SkRegion::kIntersect_Op);
987        canvas->clipPath(path2, SkRegion::kXOR_Op);
988        bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
989        REPORTER_ASSERT(reporter, true == nonEmpty);
990        REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
991        REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
992        REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
993        REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
994    }
995}
996
997static void test_cull_rect_reset(skiatest::Reporter* reporter) {
998    SkPictureRecorder recorder;
999    SkRect bounds = SkRect::MakeWH(10, 10);
1000    SkRTreeFactory factory;
1001    SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
1002    bounds = SkRect::MakeWH(100, 100);
1003    SkPaint paint;
1004    canvas->drawRect(bounds, paint);
1005    canvas->drawRect(bounds, paint);
1006    SkAutoTUnref<const SkPicture> p(recorder.endRecordingAsPicture(bounds));
1007    const SkBigPicture* picture = p->asSkBigPicture();
1008    REPORTER_ASSERT(reporter, picture);
1009
1010    SkRect finalCullRect = picture->cullRect();
1011    REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
1012    REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
1013    REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
1014    REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
1015
1016    const SkBBoxHierarchy* pictureBBH = picture->bbh();
1017    SkRect bbhCullRect = pictureBBH->getRootBound();
1018    REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
1019    REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
1020    REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
1021    REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
1022}
1023
1024
1025/**
1026 * A canvas that records the number of clip commands.
1027 */
1028class ClipCountingCanvas : public SkCanvas {
1029public:
1030    ClipCountingCanvas(int width, int height)
1031        : INHERITED(width, height)
1032        , fClipCount(0){
1033    }
1034
1035    virtual void onClipRect(const SkRect& r,
1036                            SkRegion::Op op,
1037                            ClipEdgeStyle edgeStyle) override {
1038        fClipCount += 1;
1039        this->INHERITED::onClipRect(r, op, edgeStyle);
1040    }
1041
1042    virtual void onClipRRect(const SkRRect& rrect,
1043                             SkRegion::Op op,
1044                             ClipEdgeStyle edgeStyle)override {
1045        fClipCount += 1;
1046        this->INHERITED::onClipRRect(rrect, op, edgeStyle);
1047    }
1048
1049    virtual void onClipPath(const SkPath& path,
1050                            SkRegion::Op op,
1051                            ClipEdgeStyle edgeStyle) override {
1052        fClipCount += 1;
1053        this->INHERITED::onClipPath(path, op, edgeStyle);
1054    }
1055
1056    void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override {
1057        fClipCount += 1;
1058        this->INHERITED::onClipRegion(deviceRgn, op);
1059    }
1060
1061    unsigned getClipCount() const { return fClipCount; }
1062
1063private:
1064    unsigned fClipCount;
1065
1066    typedef SkCanvas INHERITED;
1067};
1068
1069static void test_clip_expansion(skiatest::Reporter* reporter) {
1070    SkPictureRecorder recorder;
1071    SkCanvas* canvas = recorder.beginRecording(10, 10);
1072
1073    canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
1074    // The following expanding clip should not be skipped.
1075    canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
1076    // Draw something so the optimizer doesn't just fold the world.
1077    SkPaint p;
1078    p.setColor(SK_ColorBLUE);
1079    canvas->drawPaint(p);
1080    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1081
1082    ClipCountingCanvas testCanvas(10, 10);
1083    picture->playback(&testCanvas);
1084
1085    // Both clips should be present on playback.
1086    REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
1087}
1088
1089static void test_hierarchical(skiatest::Reporter* reporter) {
1090    SkBitmap bm;
1091    make_bm(&bm, 10, 10, SK_ColorRED, true);
1092
1093    SkPictureRecorder recorder;
1094
1095    recorder.beginRecording(10, 10);
1096    SkAutoTUnref<SkPicture> childPlain(recorder.endRecording());
1097    REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
1098
1099    recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
1100    SkAutoTUnref<SkPicture> childWithBitmap(recorder.endRecording());
1101    REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
1102
1103    {
1104        SkCanvas* canvas = recorder.beginRecording(10, 10);
1105        canvas->drawPicture(childPlain);
1106        SkAutoTUnref<SkPicture> parentPP(recorder.endRecording());
1107        REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
1108    }
1109    {
1110        SkCanvas* canvas = recorder.beginRecording(10, 10);
1111        canvas->drawPicture(childWithBitmap);
1112        SkAutoTUnref<SkPicture> parentPWB(recorder.endRecording());
1113        REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
1114    }
1115    {
1116        SkCanvas* canvas = recorder.beginRecording(10, 10);
1117        canvas->drawBitmap(bm, 0, 0);
1118        canvas->drawPicture(childPlain);
1119        SkAutoTUnref<SkPicture> parentWBP(recorder.endRecording());
1120        REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
1121    }
1122    {
1123        SkCanvas* canvas = recorder.beginRecording(10, 10);
1124        canvas->drawBitmap(bm, 0, 0);
1125        canvas->drawPicture(childWithBitmap);
1126        SkAutoTUnref<SkPicture> parentWBWB(recorder.endRecording());
1127        REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
1128    }
1129}
1130
1131static void test_gen_id(skiatest::Reporter* reporter) {
1132
1133    SkPictureRecorder recorder;
1134    recorder.beginRecording(0, 0);
1135    SkAutoTUnref<SkPicture> empty(recorder.endRecording());
1136
1137    // Empty pictures should still have a valid ID
1138    REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
1139
1140    SkCanvas* canvas = recorder.beginRecording(1, 1);
1141    canvas->drawARGB(255, 255, 255, 255);
1142    SkAutoTUnref<SkPicture> hasData(recorder.endRecording());
1143    // picture should have a non-zero id after recording
1144    REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
1145
1146    // both pictures should have different ids
1147    REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
1148}
1149
1150static void test_typeface(skiatest::Reporter* reporter) {
1151    SkPictureRecorder recorder;
1152    SkCanvas* canvas = recorder.beginRecording(10, 10);
1153    SkPaint paint;
1154    paint.setTypeface(SkTypeface::CreateFromName("Arial", SkTypeface::kItalic));
1155    canvas->drawText("Q", 1, 0, 10, paint);
1156    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1157    REPORTER_ASSERT(reporter, picture->hasText());
1158    SkDynamicMemoryWStream stream;
1159    picture->serialize(&stream);
1160}
1161
1162DEF_TEST(Picture, reporter) {
1163    test_typeface(reporter);
1164#ifdef SK_DEBUG
1165    test_deleting_empty_picture();
1166    test_serializing_empty_picture();
1167#else
1168    test_bad_bitmap();
1169#endif
1170    test_unbalanced_save_restores(reporter);
1171    test_peephole();
1172#if SK_SUPPORT_GPU
1173    test_gpu_veto(reporter);
1174#endif
1175    test_has_text(reporter);
1176    test_images_are_found_by_willPlayBackBitmaps(reporter);
1177    test_analysis(reporter);
1178    test_bitmap_with_encoded_data(reporter);
1179    test_clip_bound_opt(reporter);
1180    test_clip_expansion(reporter);
1181    test_hierarchical(reporter);
1182    test_gen_id(reporter);
1183    test_savelayer_extraction(reporter);
1184    test_cull_rect_reset(reporter);
1185}
1186
1187static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
1188    const SkPaint paint;
1189    const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
1190    const SkIRect irect =  { 2, 2, 3, 3 };
1191
1192    // Don't care what these record, as long as they're legal.
1193    canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
1194    canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
1195    canvas->drawBitmapNine(bitmap, irect, rect, &paint);
1196    canvas->drawSprite(bitmap, 1, 1);
1197}
1198
1199static void test_draw_bitmaps(SkCanvas* canvas) {
1200    SkBitmap empty;
1201    draw_bitmaps(empty, canvas);
1202    empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
1203    draw_bitmaps(empty, canvas);
1204}
1205
1206DEF_TEST(Picture_EmptyBitmap, r) {
1207    SkPictureRecorder recorder;
1208    test_draw_bitmaps(recorder.beginRecording(10, 10));
1209    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1210}
1211
1212DEF_TEST(Canvas_EmptyBitmap, r) {
1213    SkBitmap dst;
1214    dst.allocN32Pixels(10, 10);
1215    SkCanvas canvas(dst);
1216
1217    test_draw_bitmaps(&canvas);
1218}
1219
1220DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
1221    // This test is from crbug.com/344987.
1222    // The commands are:
1223    //   saveLayer with paint that modifies alpha
1224    //     drawBitmapRect
1225    //     drawBitmapRect
1226    //   restore
1227    // The bug was that this structure was modified so that:
1228    //  - The saveLayer and restore were eliminated
1229    //  - The alpha was only applied to the first drawBitmapRectToRect
1230
1231    // This test draws blue and red squares inside a 50% transparent
1232    // layer.  Both colours should show up muted.
1233    // When the bug is present, the red square (the second bitmap)
1234    // shows upwith full opacity.
1235
1236    SkBitmap blueBM;
1237    make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
1238    SkBitmap redBM;
1239    make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
1240    SkPaint semiTransparent;
1241    semiTransparent.setAlpha(0x80);
1242
1243    SkPictureRecorder recorder;
1244    SkCanvas* canvas = recorder.beginRecording(100, 100);
1245    canvas->drawARGB(0, 0, 0, 0);
1246
1247    canvas->saveLayer(0, &semiTransparent);
1248    canvas->drawBitmap(blueBM, 25, 25);
1249    canvas->drawBitmap(redBM, 50, 50);
1250    canvas->restore();
1251
1252    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1253
1254    // Now replay the picture back on another canvas
1255    // and check a couple of its pixels.
1256    SkBitmap replayBM;
1257    make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
1258    SkCanvas replayCanvas(replayBM);
1259    picture->playback(&replayCanvas);
1260    replayCanvas.flush();
1261
1262    // With the bug present, at (55, 55) we would get a fully opaque red
1263    // intead of a dark red.
1264    REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
1265    REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
1266}
1267
1268struct CountingBBH : public SkBBoxHierarchy {
1269    mutable int searchCalls;
1270    SkRect rootBound;
1271
1272    CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
1273
1274    void search(const SkRect& query, SkTDArray<int>* results) const override {
1275        this->searchCalls++;
1276    }
1277
1278    void insert(const SkRect[], int) override {}
1279    virtual size_t bytesUsed() const override { return 0; }
1280    SkRect getRootBound() const override { return rootBound; }
1281};
1282
1283class SpoonFedBBHFactory : public SkBBHFactory {
1284public:
1285    explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
1286    SkBBoxHierarchy* operator()(const SkRect&) const override {
1287        return SkRef(fBBH);
1288    }
1289private:
1290    SkBBoxHierarchy* fBBH;
1291};
1292
1293// When the canvas clip covers the full picture, we don't need to call the BBH.
1294DEF_TEST(Picture_SkipBBH, r) {
1295    SkRect bound = SkRect::MakeWH(320, 240);
1296    CountingBBH bbh(bound);
1297    SpoonFedBBHFactory factory(&bbh);
1298
1299    SkPictureRecorder recorder;
1300    SkCanvas* c = recorder.beginRecording(bound, &factory);
1301    // Record a few ops so we don't hit a small- or empty- picture optimization.
1302        c->drawRect(bound, SkPaint());
1303        c->drawRect(bound, SkPaint());
1304    SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
1305
1306    SkCanvas big(640, 480), small(300, 200);
1307
1308    picture->playback(&big);
1309    REPORTER_ASSERT(r, bbh.searchCalls == 0);
1310
1311    picture->playback(&small);
1312    REPORTER_ASSERT(r, bbh.searchCalls == 1);
1313}
1314
1315DEF_TEST(Picture_BitmapLeak, r) {
1316    SkBitmap mut, immut;
1317    mut.allocN32Pixels(300, 200);
1318    immut.allocN32Pixels(300, 200);
1319    immut.setImmutable();
1320    SkASSERT(!mut.isImmutable());
1321    SkASSERT(immut.isImmutable());
1322
1323    // No one can hold a ref on our pixels yet.
1324    REPORTER_ASSERT(r, mut.pixelRef()->unique());
1325    REPORTER_ASSERT(r, immut.pixelRef()->unique());
1326
1327    SkAutoTUnref<const SkPicture> pic;
1328    {
1329        // we want the recorder to go out of scope before our subsequent checks, so we
1330        // place it inside local braces.
1331        SkPictureRecorder rec;
1332        SkCanvas* canvas = rec.beginRecording(1920, 1200);
1333            canvas->drawBitmap(mut, 0, 0);
1334            canvas->drawBitmap(immut, 800, 600);
1335        pic.reset(rec.endRecording());
1336    }
1337
1338    // The picture shares the immutable pixels but copies the mutable ones.
1339    REPORTER_ASSERT(r, mut.pixelRef()->unique());
1340    REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1341
1342    // When the picture goes away, it's just our bitmaps holding the refs.
1343    pic.reset(nullptr);
1344    REPORTER_ASSERT(r, mut.pixelRef()->unique());
1345    REPORTER_ASSERT(r, immut.pixelRef()->unique());
1346}
1347
1348// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
1349DEF_TEST(Picture_getRecordingCanvas, r) {
1350    SkPictureRecorder rec;
1351    REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1352    for (int i = 0; i < 3; i++) {
1353        rec.beginRecording(100, 100);
1354        REPORTER_ASSERT(r, rec.getRecordingCanvas());
1355        rec.endRecording()->unref();
1356        REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1357    }
1358}
1359
1360DEF_TEST(MiniRecorderLeftHanging, r) {
1361    // Any shader or other ref-counted effect will do just fine here.
1362    SkPaint paint;
1363    paint.setShader(SkShader::CreateColorShader(SK_ColorRED))->unref();
1364
1365    SkMiniRecorder rec;
1366    REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
1367    // Don't call rec.detachPicture().  Test succeeds by not asserting or leaking the shader.
1368}
1369
1370DEF_TEST(Picture_preserveCullRect, r) {
1371    SkPictureRecorder recorder;
1372
1373    SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
1374    c->clear(SK_ColorCYAN);
1375
1376    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
1377    SkDynamicMemoryWStream wstream;
1378    picture->serialize(&wstream);
1379
1380    SkAutoTDelete<SkStream> rstream(wstream.detachAsStream());
1381    SkAutoTUnref<SkPicture> deserializedPicture(SkPicture::CreateFromStream(rstream));
1382
1383    REPORTER_ASSERT(r, SkToBool(deserializedPicture));
1384    REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
1385    REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
1386    REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
1387    REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
1388}
1389