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