1b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik/*
25ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Copyright (C) 2016 The Android Open Source Project
3b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
4b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Licensed under the Apache License, Version 2.0 (the "License");
5b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * you may not use this file except in compliance with the License.
6b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * You may obtain a copy of the License at
7b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
8b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *      http://www.apache.org/licenses/LICENSE-2.0
9b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
10b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Unless required by applicable law or agreed to in writing, software
11b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * distributed under the License is distributed on an "AS IS" BASIS,
12b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * See the License for the specific language governing permissions and
14b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * limitations under the License.
15b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */
16b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
17b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <gtest/gtest.h>
18b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
19b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <BakedOpState.h>
20d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik#include <DeferredLayerUpdater.h>
21f158b49c888f722194afe5a80539a2b020c130bcChris Craik#include <FrameBuilder.h>
228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik#include <LayerUpdateQueue.h>
23b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordedOp.h>
24b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordingCanvas.h>
258160f20b0aca8c6595d4b385d673f59b6bcd16a4Chris Craik#include <tests/common/TestUtils.h>
26b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
27b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <unordered_map>
28b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
29b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace android {
30b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace uirenderer {
31b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
326e068c0182f6f85bccb855a647510724d1c65a13Chris Craikconst FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
336e068c0182f6f85bccb855a647510724d1c65a13Chris Craik
346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik/**
355854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual class implemented by each test to redirect static operation / state transitions to
365854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * virtual methods.
376fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
385854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * and allows Renderer vs Dispatching behavior to be merged.
406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * onXXXOp methods fail by default - tests should override ops they expect
42d3daa3198e2212c985c634821682d5819346b653Chris Craik * startRepaintLayer fails by default - tests should override if expected
436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * startFrame/endFrame do nothing by default - tests should override to intercept
446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik */
455854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestRendererBase {
466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikpublic:
475854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    virtual ~TestRendererBase() {}
48d3daa3198e2212c985c634821682d5819346b653Chris Craik    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
4974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        ADD_FAILURE() << "Temporary layers not expected in this test";
50a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        return nullptr;
51a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    virtual void recycleTemporaryLayer(OffscreenBuffer*) {
5374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        ADD_FAILURE() << "Temporary layers not expected in this test";
5474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    }
5598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
56a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer repaint not expected in this test";
57a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
58a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void endLayer() {
59a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer updates not expected in this test";
60a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
6198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
62e4db79de127cfe961195f52907af8451026eaa20Chris Craik    virtual void endFrame(const Rect& repaintRect) {}
635854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
6415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for single draw methods
6515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
66a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void on##Type(const Type&, const BakedOpState&) { \
67a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << #Type " not expected in this test"; \
68a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
697cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X)
7015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
7215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for merged draw methods
7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
7515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
7615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
777cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X)
7815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
805854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int getIndex() { return mIndex; }
815854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
825854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikprotected:
835854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int mIndex = 0;
845854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik};
856fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
865854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik/**
875854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Dispatches all static methods to similar formed methods on renderer, which fail by default but
888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * are overridden by subclasses per test.
895854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik */
905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestDispatcher {
915854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikpublic:
9215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define single op methods, which redirect to TestRendererBase
9315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
945854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
955854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik        renderer.on##Type(op, state); \
966fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
977cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X);
9815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
9915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
10015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define merged op methods, which redirect to TestRendererBase
10115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
10215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
10315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        renderer.onMerged##Type##s(opList); \
10415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
1057cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X);
10615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
1076fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik};
108b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1095854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass FailRenderer : public TestRendererBase {};
1106fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1113a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simple) {
112d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleTestRenderer : public TestRendererBase {
113d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
11498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
115d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
116d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(100u, width);
117d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(200u, height);
118d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
119d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
120d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
121d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
122d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
123d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
124d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
125e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
126d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
127d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
128d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
129d3daa3198e2212c985c634821682d5819346b653Chris Craik
1308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
1318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
132ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
134b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawBitmap(bitmap, 10, 10, nullptr);
135b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
1369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
1379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
1389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
1399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleTestRenderer renderer;
141f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1425854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
1436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
1446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1453a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
146386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    class SimpleStrokeTestRenderer : public TestRendererBase {
147386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    public:
148386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
149386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(0, mIndex++);
150386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            // even though initial bounds are empty...
151386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_TRUE(op.unmappedBounds.isEmpty())
152386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "initial bounds should be empty, since they're unstroked";
153386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
154386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "final bounds should account for stroke";
155386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        }
156386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    };
157386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
158386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
159386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
160386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        SkPaint strokedPaint;
161386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        strokedPaint.setStrokeWidth(10);
162386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        canvas.drawPoint(50, 50, strokedPaint);
163386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    });
1649cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
1659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
1669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
1679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
168386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    SimpleStrokeTestRenderer renderer;
169f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
170386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    EXPECT_EQ(1, renderer.getIndex());
171386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik}
172386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
1733a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
1748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
176eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
1776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
1786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
1806fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
1819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
1829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
1839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
184b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1855854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
186f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
187b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
188b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1893a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
190a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
191d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleBatchingTestRenderer : public TestRendererBase {
192d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
193d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
194a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
195d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
196d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
197a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
198d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
199d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
200d3daa3198e2212c985c634821682d5819346b653Chris Craik
2018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
2028d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
20315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
20415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
206b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
207b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
208eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
209a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
210b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
211b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
212b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawBitmap(bitmap, 5, 0, nullptr);
213b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
214b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
215b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
2169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
2179cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
2189cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
219b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
2205854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
221f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
222a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
22315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
224a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
225a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
2269cd1bbe5c9e14472e631d8cc10005613925f34afChris CraikRENDERTHREAD_TEST(FrameBuilder, deferRenderNode_translateClip) {
2279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase {
2289cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    public:
2299cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(0, mIndex++);
2319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds);
2329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom,
2339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                    state.computedState.clipSideFlags);
2349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        }
2359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    };
2369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto node = TestUtils::createNode(0, 0, 100, 100,
2389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
2399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
2409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    });
2419cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
2449cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
2459cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            *TestUtils::getSyncedNode(node));
2469cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2479cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    DeferRenderNodeTranslateClipTestRenderer renderer;
2489cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2499cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    EXPECT_EQ(1, renderer.getIndex());
2509cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik}
2519cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2529cd1bbe5c9e14472e631d8cc10005613925f34afChris CraikRENDERTHREAD_TEST(FrameBuilder, deferRenderNodeScene) {
2539cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    class DeferRenderNodeSceneTestRenderer : public TestRendererBase {
2549cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    public:
2559cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            const Rect& clippedBounds = state.computedState.clippedBounds;
2579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            Matrix4 expected;
2589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            switch (mIndex++) {
2599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 0:
2609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // background - left side
2619cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
2629cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(100, 100, 0);
2639cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2649cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 1:
2659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // background - top side
2669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
2679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(100, 100, 0);
2689cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2699cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 2:
2709cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // content
2719cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
2729cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(-50, -50, 0);
2739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 3:
2759cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // overlay
2769cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
2779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            default:
2799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                ADD_FAILURE() << "Too many rects observed";
2809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            }
2819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(expected, state.computedState.transform);
2829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        }
2839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    };
2849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    std::vector<sp<RenderNode>> nodes;
2869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    SkPaint transparentPaint;
2879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    transparentPaint.setAlpha(128);
2889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // backdrop
2909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    nodes.push_back(TestUtils::createNode(100, 100, 700, 500, // 600x400
2919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
2929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 600, 400, transparentPaint);
2939cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
2949cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // content
2969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    Rect contentDrawBounds(150, 150, 650, 450); // 500x300
2979cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    nodes.push_back(TestUtils::createNode(0, 0, 800, 600,
2989cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
2999cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 800, 600, transparentPaint);
3009cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
3019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // overlay
3039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    nodes.push_back(TestUtils::createNode(0, 0, 800, 600,
3049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
3059cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 800, 200, transparentPaint);
3069cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
3079cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3089cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    for (auto& node : nodes) {
3099cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        TestUtils::syncHierarchyPropertiesAndDisplayList(node);
3109cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }
3119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
3139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
3149cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
3159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    DeferRenderNodeSceneTestRenderer renderer;
3179cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3189cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    EXPECT_EQ(4, renderer.getIndex());
3199cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik}
3209cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3216246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
3226246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyNoFbo0TestRenderer : public TestRendererBase {
3236246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
3246246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
3256246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
3266246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3276246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
3286246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
3296246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3306246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
3316246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
3329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // Use layer update constructor, so no work is enqueued for Fbo0
3339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    LayerUpdateQueue emptyLayerUpdateQueue;
3349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(emptyLayerUpdateQueue, sLightGeometry, Caches::getInstance());
3356246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyNoFbo0TestRenderer renderer;
3366246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3376246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
3386246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
3396246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
3406246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyWithFbo0TestRenderer : public TestRendererBase {
3416246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
3426246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
3436246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
3446246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3456246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
3466246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
3476246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3486246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
3496246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
3506246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
3516246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        // no drawn content
3526246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
3536246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
3549cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // Draw, but pass node without draw content, so no work is done for primary frame
3559cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
3569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
3579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
3589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3596246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyWithFbo0TestRenderer renderer;
3606246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3616246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
3626246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            " but fbo0 update lifecycle should still be observed";
3636246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
3646246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
36580d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikRENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
36680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
36780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
36880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
36980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(mIndex++, 0) << "Should be one rect";
37080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds)
37180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                    << "Last rect should occlude others.";
37280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
37380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
37480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
37580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
37680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
37780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
37880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
37980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
38080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
38180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // Damage (and therefore clip) is same as last draw, subset of renderable area.
38280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // This means last op occludes other contents, and they'll be rejected to avoid overdraw.
3839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200,
3849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
3859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
38680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
38780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
38880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
38980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
39080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawRectsTestRenderer renderer;
39180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
39280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
39380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
39480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
39580d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikRENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
39680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    static SkBitmap opaqueBitmap = TestUtils::createSkBitmap(50, 50,
39780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            SkColorType::kRGB_565_SkColorType);
39880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    static SkBitmap transpBitmap = TestUtils::createSkBitmap(50, 50,
39980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            SkColorType::kAlpha_8_SkColorType);
40080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
40180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
40280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
40380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            switch(mIndex++) {
40480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 0:
40580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                EXPECT_EQ(opaqueBitmap.pixelRef(), op.bitmap->pixelRef());
40680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
40780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 1:
40880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                EXPECT_EQ(transpBitmap.pixelRef(), op.bitmap->pixelRef());
40980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
41080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            default:
41180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                ADD_FAILURE() << "Only two ops expected.";
41280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            }
41380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
41480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
41580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
41680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    auto node = TestUtils::createNode(0, 0, 50, 50,
41780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
41880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
41980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
42080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
42180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
42280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        // only the below draws should remain, since they're
42380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawBitmap(opaqueBitmap, 0, 0, nullptr);
42480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
42580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
4269cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50,
4279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
4289cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
42980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
43080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
43180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
43280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
43380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawBitmapsTestRenderer renderer;
43480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
435a82ffc549bd6dbf8cfc6f4d646d0f458dca54014sergeyv    EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
43680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
43780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
4383a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
43993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
44093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
44193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
44293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
44393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
44493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
44593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
44693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
44793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
44893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
44993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
45093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    auto node = TestUtils::createNode(0, 0, 100, 100,
45193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
45293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
45393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
45493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
45593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
45693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 0, 40, nullptr);
45793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
45893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
45993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
46093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 0, nullptr);
46193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
46293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
46393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
46493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 80, 40, nullptr);
46593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
46693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
46793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
46893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 70, nullptr);
46993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
47093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
4719cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
4729cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
4739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
4749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
47593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
476f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
47793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
47893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
47993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
4803a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textMerging) {
481d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
482d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
483d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
484d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
485d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
486d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
487d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
488d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
489d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
490d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
491d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
492d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
493d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            [](RenderProperties& props, TestCanvas& canvas) {
494d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
495d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
496d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
497d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
498dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
499dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
500d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
5019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
5029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
5039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
5049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
505d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
506f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
507d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
508d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
509d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
5103a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
511a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
512a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
513a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
514a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
515a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
516a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
51715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
51815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
51915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
52015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
521a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
522a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
5238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 2000,
5248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
525a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
526a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
527a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
528a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setStrikeThruText(true);
52942a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
530a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
531dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
532a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
533a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
5349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
5359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000,
5369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
5379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
5389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
539a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
540f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
541a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
542d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
543b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
544b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
5457c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craikstatic auto styles = {
5467c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
5477c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5483a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStyle) {
5497c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    class TextStyleTestRenderer : public TestRendererBase {
5507c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    public:
5517c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
5527c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(0, mIndex);
5537c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(3u, opList.count);
5547c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            mIndex += opList.count;
5557c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5567c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            int index = 0;
5577c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            for (auto style : styles) {
5587c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                auto state = opList.states[index++];
5597c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(style, state->op->paint->getStyle())
5607c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Remainder of validation relies upon stable merged order";
5617c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(0, state->computedState.clipSideFlags)
5627c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Clipped bounds validation requires unclipped ops";
5637c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            }
5647c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5657c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect fill = opList.states[0]->computedState.clippedBounds;
5667c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect stroke = opList.states[1]->computedState.clippedBounds;
5677c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
5687c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                    << "Stroke+Fill should be same as stroke";
5697c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5707c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_TRUE(stroke.contains(fill));
5717c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_FALSE(fill.contains(stroke));
5727c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
57379abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            // outset by half the stroke width
5747c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect outsetFill(fill);
57579abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            outsetFill.outset(5);
5767c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, outsetFill);
5777c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
5787c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    };
5797c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
5807c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
5817c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint paint;
5827c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
5837c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setAntiAlias(true);
5847c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextSize(50);
5857c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setStrokeWidth(10);
5867c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5877c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // draw 3 copies of the same text overlapping, each with a different style.
5887c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // They'll get merged, but with
5897c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        for (auto style : styles) {
5907c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            paint.setStyle(style);
591dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
5927c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
5937c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    });
5949cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
5959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
5969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
5977c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    TextStyleTestRenderer renderer;
5987c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
5997c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
6007c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik}
6017c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
602aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
603aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
604d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
605d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
606d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
607e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
608d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
609d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
610d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
611d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
612d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
613d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
614d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
615d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
616d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
617243e85b2e443def1ef47a180e824b36f513c8db8Chris Craik            SkMatrix::MakeTrans(5, 5));
618d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
619d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
620d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
621eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
622d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
623d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
624d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
625d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
6269cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
6279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
6289cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6299cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
631aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerClipLocalMatrixTestRenderer renderer;
632f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
633d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
634d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
635d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
636aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
637aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
638aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    public:
639aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
640aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_EQ(0, mIndex++);
641aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
642aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            Matrix4 expected;
643aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            expected.loadTranslate(35, 45, 0);
644aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
645aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        }
646aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    };
647aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
648aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
649aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
650aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
651aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
652aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
653aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.save(SaveFlags::MatrixClip);
654aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.translate(30, 40);
655aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
656aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.restore();
657aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
658aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
6599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
6609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6619cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6629cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
663aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerCombineMatricesTestRenderer renderer;
664aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
665aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    EXPECT_EQ(1, renderer.getIndex());
666aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
667aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
668aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
669aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
670aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
671aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
672aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
673aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
674aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
675aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
676aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
6779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
6789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
6799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
682aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FailRenderer renderer;
683aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
684aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
685aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
6863a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, functor_reject) {
687223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
688223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
689223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
690223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
691223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
692223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
693223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
694223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
695223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
696223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
697223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
698223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
699cd1c3eba69d044b551cededad75474038f919890John Reck        canvas.callDrawGLFunction(&noopFunctor, nullptr);
700223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
701223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
7029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7033a5811b50157e7ba50854caf957e806aee794d39Chris Craik            sLightGeometry, Caches::getInstance());
7049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView));
7059cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
706223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
707223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
708223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
709223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
710223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
711a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikRENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
712a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    class ColorTestRenderer : public TestRendererBase {
713a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    public:
714a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
715a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(0, mIndex++);
716a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
717a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik                    << "Color op should be expanded to bounds of surrounding";
718a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        }
719a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    };
720a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
721a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
722a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
723a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        props.setClipToBounds(false);
724a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
725a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    });
726a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
7279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
728a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            sLightGeometry, Caches::getInstance());
7299cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView));
7309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
731a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    ColorTestRenderer renderer;
732a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
733a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
734a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik}
735a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
736a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikTEST(FrameBuilder, renderNode) {
737d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
738d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
739d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
740d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
741d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
7425430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
743d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
744d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
745d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
746d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
747d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
748d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
749d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
750d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
751d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
752d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
753d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
754d3daa3198e2212c985c634821682d5819346b653Chris Craik
7558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(10, 10, 110, 110,
7568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
757b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
758b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
759b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
760b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
761b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
7628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
763d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
764ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
765ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
766ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
767ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
768eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
769ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
770d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
771ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
772b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
773b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
7749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7759cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
7769cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
7779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
7785854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
779f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
780223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
781b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
782b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
7833a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clipped) {
784d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
785d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
786d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
787d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
788d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
789e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
790d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
791d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
792d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
793d3daa3198e2212c985c634821682d5819346b653Chris Craik
7948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
796ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
797ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawBitmap(bitmap, 0, 0, nullptr);
798ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
799ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
8009cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // clip to small area, should see in receiver
8019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200,
8029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
8039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
8049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8055854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
806f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
807ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
808ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
8093a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
810d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
811d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
812d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
813d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
814d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
815d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
816d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
817d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
818d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
819d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
820d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
821d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
822d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
823d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
8245430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
825e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
826d3daa3198e2212c985c634821682d5819346b653Chris Craik
827d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
828d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
829d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
830d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
831d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
832d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
833d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
834e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
835d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
836d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
83774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
83874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
83974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(nullptr, offscreenBuffer);
84074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
841d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
842d3daa3198e2212c985c634821682d5819346b653Chris Craik
8438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
8448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
845eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
8466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
8476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
8486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
8499cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8509cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
8519cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
8529cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
8539cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8545854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
855f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
85674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(5, renderer.getIndex());
857b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
8586fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
8593a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
860d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
861d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
862d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
863d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
864d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
865d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
866d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
867d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
868d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
869d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
870d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
871d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
872d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
873d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
874d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
875d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
876d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
877d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
878d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
879d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
880d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
881d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
882d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
883d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
88498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
885d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
886d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
887e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
888d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
889d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
890d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
891d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
892d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
8935430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
894d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
8955430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
896d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
897d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
898d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
899d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
900d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
901d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
9025430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
903d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
904d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
9055430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
906d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
907d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
90874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
90974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            const int index = mIndex++;
91074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            // order isn't important, but we need to see both
91174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            if (index == 10) {
91274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
91374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else if (index == 11) {
91474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
91574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else { ADD_FAILURE(); }
91674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
917d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
918d3daa3198e2212c985c634821682d5819346b653Chris Craik
9198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 800, 800,
9208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
921eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
9226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
9236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
924eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
9256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
9266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
9276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
9286fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
9296fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
9306fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
9316fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
9326fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800,
9349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
9359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
9369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
9375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
938f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
93974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(12, renderer.getIndex());
9406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
9416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9423a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
9438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        auto node = TestUtils::createNode(0, 0, 200, 200,
9448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
945eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
9466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
947eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
9486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9496fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
9506fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
9516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9526fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
9536fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
9546fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
9559cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
9569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
9579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
9589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
9596fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9605854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
9616fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
962f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
963b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
9646fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9653a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
966b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
967b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
968b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
969b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
970b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
9717435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
972b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
973b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
974b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
975b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
976b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
977b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
978b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
979b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
980b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
981b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
982b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
983b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
984b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
985b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
986b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
987b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
988b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
9897435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
990b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
991b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
992b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
993b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
994b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
995b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
996eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
997b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
998b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
999b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
10009cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
10019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
10029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
10039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
10049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1005b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
1006f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1007b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
1008b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1009b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
101045e83338e525070702c12d68d904107989f439f9Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_round) {
101145e83338e525070702c12d68d904107989f439f9Chris Craik    class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase {
101245e83338e525070702c12d68d904107989f439f9Chris Craik    public:
101345e83338e525070702c12d68d904107989f439f9Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
101445e83338e525070702c12d68d904107989f439f9Chris Craik            EXPECT_EQ(0, mIndex++);
101545e83338e525070702c12d68d904107989f439f9Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
101645e83338e525070702c12d68d904107989f439f9Chris Craik                    << "Bounds rect should round out";
101745e83338e525070702c12d68d904107989f439f9Chris Craik        }
101845e83338e525070702c12d68d904107989f439f9Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {}
101945e83338e525070702c12d68d904107989f439f9Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {}
102045e83338e525070702c12d68d904107989f439f9Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
102145e83338e525070702c12d68d904107989f439f9Chris Craik            EXPECT_EQ(1, mIndex++);
102245e83338e525070702c12d68d904107989f439f9Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
102345e83338e525070702c12d68d904107989f439f9Chris Craik                    << "Bounds rect should round out";
102445e83338e525070702c12d68d904107989f439f9Chris Craik        }
102545e83338e525070702c12d68d904107989f439f9Chris Craik    };
102645e83338e525070702c12d68d904107989f439f9Chris Craik
102745e83338e525070702c12d68d904107989f439f9Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
102845e83338e525070702c12d68d904107989f439f9Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
102945e83338e525070702c12d68d904107989f439f9Chris Craik        canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
103045e83338e525070702c12d68d904107989f439f9Chris Craik                128, (SaveFlags::Flags)(0));
103145e83338e525070702c12d68d904107989f439f9Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
103245e83338e525070702c12d68d904107989f439f9Chris Craik        canvas.restore();
103345e83338e525070702c12d68d904107989f439f9Chris Craik    });
103445e83338e525070702c12d68d904107989f439f9Chris Craik
103545e83338e525070702c12d68d904107989f439f9Chris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
103645e83338e525070702c12d68d904107989f439f9Chris Craik            sLightGeometry, Caches::getInstance());
103745e83338e525070702c12d68d904107989f439f9Chris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
103845e83338e525070702c12d68d904107989f439f9Chris Craik
103945e83338e525070702c12d68d904107989f439f9Chris Craik    SaveLayerUnclippedRoundTestRenderer renderer;
104045e83338e525070702c12d68d904107989f439f9Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
104145e83338e525070702c12d68d904107989f439f9Chris Craik    EXPECT_EQ(2, renderer.getIndex());
104245e83338e525070702c12d68d904107989f439f9Chris Craik}
104345e83338e525070702c12d68d904107989f439f9Chris Craik
10443a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
1045b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
1046b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
1047b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1048b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1049b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
1050b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
1051b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
1052b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
1053b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
1054b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
1055b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
1056b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
1057b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
1058b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
1059b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
1060b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
1061b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1062b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1063b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
1064b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
1065b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
1066b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
1067b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
1068b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
1069b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
1070b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1071b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1072b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
1073b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1074b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1075b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
1076b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1077b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1078b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1079b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1080b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1081b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1082eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
1083b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
1084eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
1085eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
1086eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
1087eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
1088b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
1089b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
1090b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
10919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
10929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
10939cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
10949cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
10959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1096b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
1097f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1098b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
1099b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
1100b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1101b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
11023a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
11034876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
11044876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
11054876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
11064876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
11074876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11084876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
11094876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
11104876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
11114876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
11124876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
11134876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
11144876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
11154876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
11164876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
11174876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11184876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
11194876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
11204876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11214876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
11224876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
11234876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11244876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
11254876de16e34622634266d09522c9153c78c7c2fbChris Craik
11264876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
11274876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
11284876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
11294876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
11304876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
11314876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
11324876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
11334876de16e34622634266d09522c9153c78c7c2fbChris Craik
11344876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
11359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
11369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
11379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
11389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
11394876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
11404876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
11414876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
11424876de16e34622634266d09522c9153c78c7c2fbChris Craik}
11434876de16e34622634266d09522c9153c78c7c2fbChris Craik
11443a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
11454876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
11464876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
11474876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
11484876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
11494876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
11504876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
11514876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
11524876de16e34622634266d09522c9153c78c7c2fbChris Craik
11534876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
11549cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
11559cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
11569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
11579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
11584876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
11594876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
11604876de16e34622634266d09522c9153c78c7c2fbChris Craik}
11614876de16e34622634266d09522c9153c78c7c2fbChris Craik
1162b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
1163b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
1164b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
1165b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
11663a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
1167b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
1168b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
1169b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
1170b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
1171b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
1172b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1173b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1174b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1175b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
1176b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1177b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1178b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1179b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
1180b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1181b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1182b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
1183b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
1184b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
1185b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
1186b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
1187b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1188b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1189b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1190b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
1191b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1192b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
1193b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
1194b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1195b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1196b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
1197b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1198b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1199b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
120074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1201b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1202b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
1203b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
1204b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
120574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
120674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(12, mIndex++);
120774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
120874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1209b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1210b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1211b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
1212b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1213eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
1214eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
1215eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
1216b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
1217b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1218b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1219b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1220b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
12219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
12229cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600,
12239cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
12249cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
12259cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1226b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
1227f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
122874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(13, renderer.getIndex());
1229b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1230b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1231f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
1232d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
1233d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
123498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1235d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
123698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
123798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
123898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
1239d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1240d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1241d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
12420b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1243d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
1244d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
1245d3daa3198e2212c985c634821682d5819346b653Chris Craik
1246e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
1247d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
1248d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1249d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1250d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
1251d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
125298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1253d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
1254d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1255d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1256d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
1257d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1258e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1259d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
1260d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1261d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
12620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
126416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
126516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
12660b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
12670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
12680b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
126916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
127098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
12710b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
127298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
127398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
127498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
12750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12769cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(node);
12770b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12780b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
127998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
12800b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
12810b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
12839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
12849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
12859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
12869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
12870b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
1288f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
12890b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
12900b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12910b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
129298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
12930b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
12940b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1295f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
1296d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
1297d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
1298d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
1299d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
1300d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
1301d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
1302d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
1303d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1304d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
1305d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
1306d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
1307d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
130898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1309d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1310d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
1311d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
131298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
131398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
1314d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
1315d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
131698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
131798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
1318d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1319d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1320d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1321d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1322d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
1323d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
1324d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
1325d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
1326d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
1327d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1328d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1329d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1330d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1331d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1332d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
1333d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
133498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1335d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
1336d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1337d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
133898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
1339d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1340d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
134198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
134298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
1343d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
1344d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1345d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
134698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
134798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
1348d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1349d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1350e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1351d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
1352d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
135374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
135474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(13, mIndex++);
135574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1356d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1357d3daa3198e2212c985c634821682d5819346b653Chris Craik
135816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto child = TestUtils::createNode(50, 50, 150, 150,
135916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
136016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
13610b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
13620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
13630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
136416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
136598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
136698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
13670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13680b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
136916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 200, 200,
137016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
137116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
13720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
13730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
13740b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
13750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1376eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
13770b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
13780b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
137916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
138098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
138198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
13820b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
13840b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
138598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
13860b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
13870b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
13880b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
13909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
13919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
13929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
13939cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
13940b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
1395f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
139674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(14, renderer.getIndex());
13970b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13980b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
13990b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
14000b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
14010b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
14020b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14036246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14046246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, buildLayer) {
14056246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class BuildLayerTestRenderer : public TestRendererBase {
14066246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
14076246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
14086246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
14096246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
14106246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
14116246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
14126246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14136246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
14146246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
14156246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14166246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
14176246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Transform should be reset within layer";
14186246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14196246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
14206246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Damage rect should be used to clip layer content";
14216246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14226246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endLayer() override {
14236246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(2, mIndex++);
14246246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14256246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
14266246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
14276246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14286246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
14296246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
14306246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14316246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
14326246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14336246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
14346246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
14356246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        props.mutateLayerProperties().setType(LayerType::RenderLayer);
14366246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
14376246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
14386246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
14396246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14406246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // create RenderNode's layer here in same way prepareTree would
14416246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
14426246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = &layer;
14436246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14449cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
14456246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14466246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // only enqueue partial damage
14476246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
14486246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
14496246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14506246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // Draw, but pass empty node list, so no work is done for primary frame
14519cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, sLightGeometry, Caches::getInstance());
14526246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    BuildLayerTestRenderer renderer;
14536246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
14546246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(3, renderer.getIndex());
14556246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14566246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
14576246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = nullptr;
14586246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
14596246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
1460161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
1461161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
1462161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
1463161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
1464161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1465161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
146616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
14678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
1468161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
1469161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1470161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
1471161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
1472161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1473161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
14743a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, zReorder) {
1475d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ZReorderTestRenderer : public TestRendererBase {
1476d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1477d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1478d3daa3198e2212c985c634821682d5819346b653Chris Craik            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
1479d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
1480d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1481d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1482d3daa3198e2212c985c634821682d5819346b653Chris Craik
148316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 100, 100,
14848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1485161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1486161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
1487161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
1488161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
1489161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
1490161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
1491161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
1492161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
1493161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
1494161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
1495161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
1496161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
1497161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
14989cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
14999cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
15009cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
15019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1502161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
1503f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1504161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    EXPECT_EQ(10, renderer.getIndex());
1505161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1506161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
15073a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
15088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
15098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
15108d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
15118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
15128d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
15138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
15148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
15158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
15168d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
15178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
15188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
15198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
15208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1521678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
15228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
15238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
15248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
15258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1526678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1527678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1528678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1529678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
15308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
15318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
15328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
15338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
15348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1535678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
15368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
15378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
15388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
15398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1540678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
15418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
15428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
15438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
15448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
15458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
15468d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
15478d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
15488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
15498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
15508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
15518d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
15528d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
15538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
15548d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
15558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
15568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
15578d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
15588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
15598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
15608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
15618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
15628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
15638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
15648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
15658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
15668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
15678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
15688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
15698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
15708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
15718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
15728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(0, 50, 100, 100,
15738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
15748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
15758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
15768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
15778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
15788d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
15798d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
15808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1581678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1582678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1583678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1584eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
15858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
15868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
15878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
15888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
15898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
15908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
15919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
15929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
15939cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
15949cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
15958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1596f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
15978d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
15988d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
15998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1600678ff81105753656aa4822f4f675ef96dc9d2b83Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
1601678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1602678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1603678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1604678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1605678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1606678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1607678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1608678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1609678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1610678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1611678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1612678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1613678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1614678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1615678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1616678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1617678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1618678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1619678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1620678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1621678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1622678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1623678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1624678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1625678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1626678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1627678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1628678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1629678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1630678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1631678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1632678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
1633678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1634678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1635678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1636678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1637678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1638678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1639678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1640678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1641678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1642678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1643678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1644678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1645678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1646678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1647678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1648678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1649678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto child = TestUtils::createNode(100, 100, 300, 300,
1650678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1651678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1652678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1653678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1654678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1655678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1656678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1657678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1658678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1659678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1660678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1661678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1662678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1663678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1664678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1665678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1666678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1667678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1668678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1669678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1670678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1671678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1672678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
16739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
16749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1675678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1676678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
16779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
16789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
16799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
16809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
16819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
16829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1683678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1684678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1685678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1686678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1687678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1688678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1689678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1690678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1691a748c08241e43fc68c7c34767d819aef5183936eChris CraikRENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
1692a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1693a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1694a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1695a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1696a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1697a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1698a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1699a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1700a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1701a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1702a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1703a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1704a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1705a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1706a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1707a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
1708a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1709a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1710a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1711a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1712a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1713a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1714a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1715a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1716a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1717a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1718a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1719a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1720a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1721a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1722a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1723a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto child = TestUtils::createNode(0, 0, 400, 400,
1724a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1725a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
1726a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
1727a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1728a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1729a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1730a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1731a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1732a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1733a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1734a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1735a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1736a748c08241e43fc68c7c34767d819aef5183936eChris Craik
17379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
17389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
17399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
17409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1741a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1742a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1743a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1744a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1745a748c08241e43fc68c7c34767d819aef5183936eChris Craik
174698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
174798787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
174816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return TestUtils::createNode(0, 0, 100, 100,
17498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
175016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
175116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
175298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
175398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
175498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
175598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
175698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
175798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
17586e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadow) {
1759d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1760d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1761d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1762d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
176398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
17646e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
17656e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
176698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
176798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
176898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
17696e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1770d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1771d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1772d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1773d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1774d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1775161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
17768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
17778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
177898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
177998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1780d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
178198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
17829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
17839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
17849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
17859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
178698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1787f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
178898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
178998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
179098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
17916e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
179298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
179398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
179498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
179598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
179698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
179798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
179898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
179998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
18006e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
18016e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
180298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
180398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
180498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
180598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
180698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
180798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
180898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
180998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
181098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
181198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
181274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
181374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(5, mIndex++);
181474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
181598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
181698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
18178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
18188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
181998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
182098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1821eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1822d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
182398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
182498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
182598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1826d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1827d3daa3198e2212c985c634821682d5819346b653Chris Craik
18289cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
18293a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
18309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
18319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
183298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1833f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
183474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(6, renderer.getIndex());
183598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1836d3daa3198e2212c985c634821682d5819346b653Chris Craik
1837f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
183898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
183998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
184098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
184198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
184298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
184398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
184498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
18456e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
18466e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
18476e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
184898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
184998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
185098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
185198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
185298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
185398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
185498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
185598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
185698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
185798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
185898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1859d3daa3198e2212c985c634821682d5819346b653Chris Craik
18608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(50, 60, 150, 160,
186116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
186216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
186398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1864eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
186598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
186698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
186798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
186816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
186998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
187098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
187198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
187298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
187398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
187498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
187598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
187698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
187798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
18789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
187998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
188098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
18819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
18829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
18833a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
18849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
18859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
18869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
188798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1888f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
188998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
189098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
189198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
189298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1893d3daa3198e2212c985c634821682d5819346b653Chris Craik}
189476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
18953a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
189698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
189798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
189898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
189998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
190098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
190198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
190298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
190398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
190498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
190598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
190698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
19078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
19088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
190998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
191098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
191198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
191298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
19139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
19143a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
19159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
19169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
191798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1918f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
191998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
192098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
192198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1922d645640180c25c2711e99aa82ec629155f8e91baChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowClipping) {
1923d645640180c25c2711e99aa82ec629155f8e91baChris Craik    class ShadowClippingTestRenderer : public TestRendererBase {
1924d645640180c25c2711e99aa82ec629155f8e91baChris Craik    public:
1925d645640180c25c2711e99aa82ec629155f8e91baChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1926d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(0, mIndex++);
1927d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipState->rect)
1928d645640180c25c2711e99aa82ec629155f8e91baChris Craik                    << "Shadow must respect pre-barrier canvas clip value.";
1929d645640180c25c2711e99aa82ec629155f8e91baChris Craik        }
1930d645640180c25c2711e99aa82ec629155f8e91baChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1931d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(1, mIndex++);
1932d645640180c25c2711e99aa82ec629155f8e91baChris Craik        }
1933d645640180c25c2711e99aa82ec629155f8e91baChris Craik    };
1934d645640180c25c2711e99aa82ec629155f8e91baChris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
1935d645640180c25c2711e99aa82ec629155f8e91baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1936d645640180c25c2711e99aa82ec629155f8e91baChris Craik        // Apply a clip before the reorder barrier/shadow casting child is drawn.
1937d645640180c25c2711e99aa82ec629155f8e91baChris Craik        // This clip must be applied to the shadow cast by the child.
1938d645640180c25c2711e99aa82ec629155f8e91baChris Craik        canvas.clipRect(25, 25, 75, 75, SkRegion::kIntersect_Op);
1939d645640180c25c2711e99aa82ec629155f8e91baChris Craik        canvas.insertReorderBarrier(true);
1940d645640180c25c2711e99aa82ec629155f8e91baChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1941d645640180c25c2711e99aa82ec629155f8e91baChris Craik    });
1942d645640180c25c2711e99aa82ec629155f8e91baChris Craik
19439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
1944d645640180c25c2711e99aa82ec629155f8e91baChris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
19459cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
19469cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1947d645640180c25c2711e99aa82ec629155f8e91baChris Craik    ShadowClippingTestRenderer renderer;
1948d645640180c25c2711e99aa82ec629155f8e91baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1949d645640180c25c2711e99aa82ec629155f8e91baChris Craik    EXPECT_EQ(2, renderer.getIndex());
1950d645640180c25c2711e99aa82ec629155f8e91baChris Craik}
1951d645640180c25c2711e99aa82ec629155f8e91baChris Craik
195216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
195376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
1954d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
1955d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1956d3daa3198e2212c985c634821682d5819346b653Chris Craik        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1957d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
1958d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1959d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
1960d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
1961d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1962d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1963d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1964d3daa3198e2212c985c634821682d5819346b653Chris Craik
196516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
196616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
196716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
196876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
196976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
197076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
197116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
197276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
19739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
19749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
19759cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
19769cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
197776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
1978f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
197976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
198076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
198176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
19823a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
198376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
198476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
198576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
198676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
198776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
198876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
198976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
199076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
19913a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
199276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
199376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
199476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
199576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
199676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
199776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
199876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
199976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
200076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20013a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
200276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
200376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
200476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
200576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
200676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
200776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
200876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
200976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
201076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
201176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20123a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
201376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
201476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
201576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
201676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
201776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
201876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
201976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
202076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
202176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
202276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
202376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20243a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
202576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
202676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
202776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
202876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
202976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
203076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
203176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
203276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
203376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
203476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
203576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
203676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
203776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
203876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
203976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
204076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
204176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
204276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
204376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
204476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
204576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
204676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
204776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
204876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
204976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
205076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
205176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
205276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
205376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
205476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
205576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
2056161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
20578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
20588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
20598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
20608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
20618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
2062c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    Matrix4 drawLayerMatrix;
20638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
20648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
20658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
20668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
20678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
20688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
20698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
20708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
20718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
20728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
20738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
20748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
207516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
20768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
20778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
20788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
20798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
20808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
20818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
20828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
20838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
20848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
20858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
20868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
20878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
20888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
20898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
20908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
20918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
20928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
20938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
20948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
20958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
20968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
20978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
2098c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck            mOutData->drawLayerMatrix = state.computedState.transform;
20998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
210074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
210174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
210274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
21038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
21048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
21058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
21068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
21088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
210916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 10000, 10000,
211016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
21118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
21128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
21138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
211416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
211516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
211616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
211716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
211816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
21198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
21209cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
21219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
21229cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
21239cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                sLightGeometry, Caches::getInstance());
21249cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
21258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
2127f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
21288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
213074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
21318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
21328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21333a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
21348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
21358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
21368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
21378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
21388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
21398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
21408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
21415430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
21428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
21438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
21448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
21458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
21468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
2147c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    expected.loadTranslate(10, 0, 0);
2148c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    EXPECT_MATRIX_APPROX_EQ(expected, observedData.drawLayerMatrix)
2149c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck                << "expect drawLayer to be translated as part of being clipped";
21508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
21518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21523a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
21538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
21548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
21558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
21568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
21578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
21588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
21598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
21608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
21618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
21628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
21638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
21648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
21658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
21668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
21675430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
21688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
21698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
21708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21713a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
21728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
21738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
21748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
21758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
21768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
21778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
21788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
21798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
21808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
21815430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
21828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
21838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
21848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
218504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris CraikRENDERTHREAD_TEST(FrameBuilder, clip_replace) {
218604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    class ClipReplaceTestRenderer : public TestRendererBase {
218704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    public:
218804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
218904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(0, mIndex++);
219004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_TRUE(op.localClip->intersectWithRoot);
219104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(Rect(20, 10, 30, 40), state.computedState.clipState->rect)
219204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik                    << "Expect resolved clip to be intersection of viewport clip and clip op";
219304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        }
219404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    };
219504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    auto node = TestUtils::createNode(20, 20, 30, 30,
219604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
219704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        canvas.clipRect(0, -20, 10, 30, SkRegion::kReplace_Op);
219804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
219904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    });
220004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
22019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
22029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
22039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
22049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
220504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    ClipReplaceTestRenderer renderer;
220604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
220704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    EXPECT_EQ(1, renderer.getIndex());
220804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik}
220904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
22106fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
22116fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
2212