FrameBuilderTests.cpp revision 6c67f1d04591f44bccb476d715a005ad5bbdf840
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
13006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 200,
1318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
132aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
134aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        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
15806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(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) {
17406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
176eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
1776c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // 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
20106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
2028d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
203aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv
204aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10,
205aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv                kAlpha_8_SkColorType)); // Disable merging by using alpha 8 bitmap
206b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
207b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
208b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
209eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
210a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
211b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
212b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
213aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv            canvas.drawBitmap(*bitmap, 5, 0, nullptr);
214b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
215b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
216b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
2179cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
2189cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
2199cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
220b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
2215854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
222f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
223a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
22415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
225a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
226a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
2279cd1bbe5c9e14472e631d8cc10005613925f34afChris CraikRENDERTHREAD_TEST(FrameBuilder, deferRenderNode_translateClip) {
2289cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase {
2299cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    public:
2309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(0, mIndex++);
2329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds);
2339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom,
2349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                    state.computedState.clipSideFlags);
2359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        }
2369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    };
2379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
23806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
2409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
2419cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    });
2429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2449cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
2459cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
2469cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            *TestUtils::getSyncedNode(node));
2479cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2489cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    DeferRenderNodeTranslateClipTestRenderer renderer;
2499cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2509cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    EXPECT_EQ(1, renderer.getIndex());
2519cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik}
2529cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2539cd1bbe5c9e14472e631d8cc10005613925f34afChris CraikRENDERTHREAD_TEST(FrameBuilder, deferRenderNodeScene) {
2549cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    class DeferRenderNodeSceneTestRenderer : public TestRendererBase {
2559cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    public:
2569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            const Rect& clippedBounds = state.computedState.clippedBounds;
2589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            Matrix4 expected;
2599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            switch (mIndex++) {
2609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 0:
2619cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // background - left side
2629cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
2639cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(100, 100, 0);
2649cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 1:
2669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // background - top side
2679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
2689cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(100, 100, 0);
2699cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2709cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 2:
2719cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // content
2729cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
2739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                expected.loadTranslate(-50, -50, 0);
2749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2759cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            case 3:
2769cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                // overlay
2779cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
2789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                break;
2799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            default:
2809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                ADD_FAILURE() << "Too many rects observed";
2819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            }
2829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            EXPECT_EQ(expected, state.computedState.transform);
2839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        }
2849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    };
2859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    std::vector<sp<RenderNode>> nodes;
2879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    SkPaint transparentPaint;
2889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    transparentPaint.setAlpha(128);
2899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // backdrop
29106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    nodes.push_back(TestUtils::createNode<RecordingCanvas>(100, 100, 700, 500, // 600x400
2929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
2939cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 600, 400, transparentPaint);
2949cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
2959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // content
2979cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    Rect contentDrawBounds(150, 150, 650, 450); // 500x300
29806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
2999cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
3009cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 800, 600, transparentPaint);
3019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
3029cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // overlay
30406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
3059cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
3069cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        canvas.drawRect(0, 0, 800, 200, transparentPaint);
3079cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }));
3089cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3099cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    for (auto& node : nodes) {
3109cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik        TestUtils::syncHierarchyPropertiesAndDisplayList(node);
3119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    }
3129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
3149cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
3159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
3169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3179cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    DeferRenderNodeSceneTestRenderer renderer;
3189cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3199cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    EXPECT_EQ(4, renderer.getIndex());
3209cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik}
3219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3226246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
3236246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyNoFbo0TestRenderer : public TestRendererBase {
3246246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
3256246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
3266246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
3276246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3286246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
3296246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
3306246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3316246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
3326246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
3339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // Use layer update constructor, so no work is enqueued for Fbo0
3349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    LayerUpdateQueue emptyLayerUpdateQueue;
3359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(emptyLayerUpdateQueue, sLightGeometry, Caches::getInstance());
3366246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyNoFbo0TestRenderer renderer;
3376246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3386246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
3396246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
3406246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
3416246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyWithFbo0TestRenderer : public TestRendererBase {
3426246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
3436246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
3446246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
3456246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3466246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
3476246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
3486246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
3496246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
35006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
3516246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
3526246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        // no drawn content
3536246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
3546246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
3559cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // Draw, but pass node without draw content, so no work is done for primary frame
3569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
3579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
3589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
3599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
3606246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyWithFbo0TestRenderer renderer;
3616246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3626246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
3636246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            " but fbo0 update lifecycle should still be observed";
3646246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
3656246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
36680d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikRENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
36780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
36880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
36980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
37080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(mIndex++, 0) << "Should be one rect";
37180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds)
37280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                    << "Last rect should occlude others.";
37380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
37480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
37506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
37680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
37780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
37880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
37980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
38080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
38180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
38280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // Damage (and therefore clip) is same as last draw, subset of renderable area.
38380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // This means last op occludes other contents, and they'll be rejected to avoid overdraw.
3849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200,
3859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
3869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
38780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
38880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
38980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
39080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
39180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawRectsTestRenderer renderer;
39280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
39380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
39480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
39580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
39680d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikRENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
397aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv    static sk_sp<Bitmap> opaqueBitmap(TestUtils::createBitmap(50, 50,
398aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv            SkColorType::kRGB_565_SkColorType));
399aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv    static sk_sp<Bitmap> transpBitmap(TestUtils::createBitmap(50, 50,
400aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv            SkColorType::kAlpha_8_SkColorType));
40180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
40280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
40380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
40480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            switch(mIndex++) {
40580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 0:
406ec4a4b13eae2241d1613890c1c1c096bed891845sergeyv                EXPECT_EQ(opaqueBitmap.get(), op.bitmap);
40780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
40880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 1:
409ec4a4b13eae2241d1613890c1c1c096bed891845sergeyv                EXPECT_EQ(transpBitmap.get(), op.bitmap);
41080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
41180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            default:
41280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                ADD_FAILURE() << "Only two ops expected.";
41380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            }
41480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
41580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
41680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
41706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 50, 50,
41880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
41980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
42080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
421aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
42280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
42380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        // only the below draws should remain, since they're
424aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*opaqueBitmap, 0, 0, nullptr);
425aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
42680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
4279cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50,
4289cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
4299cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
43080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
43180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
43280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
43380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
43480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawBitmapsTestRenderer renderer;
43580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
436a82ffc549bd6dbf8cfc6f4d646d0f458dca54014sergeyv    EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
43780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
43880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
4393a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
44093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
44193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
44293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
44393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
44493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
44593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
44693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
44793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
44893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
44993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
45093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
45106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
45206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
453aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20));
45493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
45593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
4566c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace);
457aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 0, 40, nullptr);
45893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
45993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
4606c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace);
461aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 40, 0, nullptr);
46293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
46393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
4646c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace);
465aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 80, 40, nullptr);
46693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
46793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
4686c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace);
469aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 40, 70, nullptr);
47093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
47193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
4729cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
4739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
4749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
4759cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
47693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
477f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
47893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
47993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
48093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
481f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris CraikRENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
482f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    class RegionClipStopsMergeTestRenderer : public TestRendererBase {
483f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    public:
484f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
485f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    };
486f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
487f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
488f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        SkPath path;
489f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        path.addCircle(200, 200, 200, SkPath::kCW_Direction);
490f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        canvas.save(SaveFlags::MatrixClip);
4916c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipPath(&path, SkClipOp::kIntersect);
492f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        SkPaint paint;
493f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
494f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        paint.setAntiAlias(true);
495f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        paint.setTextSize(50);
496f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
497f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
498f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik        canvas.restore();
499f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    });
500f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik
501f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
502f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik            sLightGeometry, Caches::getInstance());
503f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
504f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik
505f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    RegionClipStopsMergeTestRenderer renderer;
506f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
507f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik    EXPECT_EQ(2, renderer.getIndex());
508f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik}
509f8f56cbb20817c295fe8c6f886dca5e2912e1996Chris Craik
5103a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textMerging) {
511d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
512d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
513d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
514d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
515d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
516d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
517d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
518d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
519d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
520d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
521d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
52206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
52306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
524d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
525d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
526d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
527d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
528dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
529dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
530d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
5319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
5329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
5339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
5349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
535d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
536f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
537d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
538d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
539d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
5403a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
541a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
542a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
543a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
544a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
545a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
546a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
54715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
54815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
54915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
55015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
551a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
552a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
55306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 2000,
5548d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
555a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
556a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
557a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
558a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setStrikeThruText(true);
55942a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
560a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
561dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
562a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
563a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
5649cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
5659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000,
5669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
5679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
5689cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
569a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
570f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
571a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
572d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
573b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
574b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
5757c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craikstatic auto styles = {
5767c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
5777c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5783a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStyle) {
5797c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    class TextStyleTestRenderer : public TestRendererBase {
5807c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    public:
5817c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
5827c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(0, mIndex);
5837c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(3u, opList.count);
5847c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            mIndex += opList.count;
5857c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5867c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            int index = 0;
5877c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            for (auto style : styles) {
5887c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                auto state = opList.states[index++];
5897c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(style, state->op->paint->getStyle())
5907c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Remainder of validation relies upon stable merged order";
5917c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(0, state->computedState.clipSideFlags)
5927c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Clipped bounds validation requires unclipped ops";
5937c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            }
5947c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
5957c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect fill = opList.states[0]->computedState.clippedBounds;
5967c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect stroke = opList.states[1]->computedState.clippedBounds;
5977c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
5987c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                    << "Stroke+Fill should be same as stroke";
5997c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
6007c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_TRUE(stroke.contains(fill));
6017c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_FALSE(fill.contains(stroke));
6027c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
60379abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            // outset by half the stroke width
6047c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect outsetFill(fill);
60579abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            outsetFill.outset(5);
6067c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, outsetFill);
6077c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
6087c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    };
60906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
61006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
6117c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint paint;
6127c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
6137c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setAntiAlias(true);
6147c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextSize(50);
6157c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setStrokeWidth(10);
6167c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
6177c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // draw 3 copies of the same text overlapping, each with a different style.
6187c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // They'll get merged, but with
6197c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        for (auto style : styles) {
6207c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            paint.setStyle(style);
621dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
6227c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
6237c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    });
6249cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
6259cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6269cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6277c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    TextStyleTestRenderer renderer;
6287c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
6297c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
6307c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik}
6317c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
632aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
633aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
634d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
635d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
636d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
637e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
638d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
639d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
640d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
641d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
642d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
643d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
644d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
645d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
646d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
647243e85b2e443def1ef47a180e824b36f513c8db8Chris Craik            SkMatrix::MakeTrans(5, 5));
648d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
64906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
650d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
651eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
6526c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect);
653d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
654d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
655d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
6569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
6579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
6589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
661aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerClipLocalMatrixTestRenderer renderer;
662f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
663d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
664d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
665d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
666aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
667aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
668aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    public:
669aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
670aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_EQ(0, mIndex++);
671aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
672aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            Matrix4 expected;
673aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            expected.loadTranslate(35, 45, 0);
674aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
675aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        }
676aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    };
677aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
678aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
679aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
680aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
68106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
682aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
683aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.save(SaveFlags::MatrixClip);
684aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.translate(30, 40);
685aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
686aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.restore();
687aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
688aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
6899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
6909cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
6919cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
6929cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
693aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerCombineMatricesTestRenderer renderer;
694aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
695aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    EXPECT_EQ(1, renderer.getIndex());
696aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
697aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
698aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
699aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
700aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
701aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
702aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
70306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
704aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
705aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
706aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
7079cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
7089cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7099cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
7109cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
7119cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
712aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FailRenderer renderer;
713aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
714aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
715aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
7163a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, functor_reject) {
717223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
718223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
719223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
720223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
721223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
722223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
723223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
724223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
725223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
72606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto scrolledFunctorView = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 1000000,
727223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
728223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
729cd1c3eba69d044b551cededad75474038f919890John Reck        canvas.callDrawGLFunction(&noopFunctor, nullptr);
730223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
731223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
7329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
7333a5811b50157e7ba50854caf957e806aee794d39Chris Craik            sLightGeometry, Caches::getInstance());
7349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView));
7359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
736223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
737223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
738223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
739223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
740223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
741a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikRENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
742a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    class ColorTestRenderer : public TestRendererBase {
743a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    public:
744a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
745a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(0, mIndex++);
746a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
747a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik                    << "Color op should be expanded to bounds of surrounding";
748a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        }
749a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    };
750a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
75106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto unclippedColorView = TestUtils::createNode<RecordingCanvas>(0, 0, 10, 10,
752a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
753a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        props.setClipToBounds(false);
754260ab726486317496bc12a57d599ea96dcde3284Mike Reed        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
755a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    });
756a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
7579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
758a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            sLightGeometry, Caches::getInstance());
7599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView));
7609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
761a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    ColorTestRenderer renderer;
762a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
763a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
764a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik}
765a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
766a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikTEST(FrameBuilder, renderNode) {
767d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
768d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
769d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
770d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
771d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
7725430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
773d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
774d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
775d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
776d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
777d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
778d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
779d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
780d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
781d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
782d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
783d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
784d3daa3198e2212c985c634821682d5819346b653Chris Craik
78506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
7868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
787b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
788b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
789b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
790b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
791b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
79206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
793d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
794ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
795ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
796ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
797ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
798eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
799ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
800d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
801ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
802b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
803b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
8049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
8059cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
8069cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
8079cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8085854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
809f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
810223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
811b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
812b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
8133a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clipped) {
814d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
815d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
816d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
817d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
818d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
819e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
820d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
821d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
822d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
823d3daa3198e2212c985c634821682d5819346b653Chris Craik
82406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
8258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
826aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(200, 200));
827aed7f58fb05a25ce2112829e77c0eb5dd268e8a7sergeyv        canvas.drawBitmap(*bitmap, 0, 0, nullptr);
828ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
829ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
8309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    // clip to small area, should see in receiver
8319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200,
8329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
8339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
8349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8355854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
836f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
837ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
838ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
8393a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
840d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
841d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
842d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
843d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
844d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
845d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
846d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
847d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
848d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
849d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
850d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
851d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
852d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
853d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
8545430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
855e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
856d3daa3198e2212c985c634821682d5819346b653Chris Craik
857d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
858d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
859d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
860d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
861d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
862d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
863d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
864e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
865d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
866d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
86774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
86874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
86974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(nullptr, offscreenBuffer);
87074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
871d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
872d3daa3198e2212c985c634821682d5819346b653Chris Craik
87306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
8748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
875eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
8766fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
8776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
8786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
8799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
8819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
8829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
8839cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
8845854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
885f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
88674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(5, renderer.getIndex());
887b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
8886fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
8893a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
890d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
891d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
892d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
893d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
894d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
895d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
896d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
897d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
898d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
899d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
900d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
901d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
902d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
903d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
904d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
905d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
906d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
907d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
908d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
909d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
910d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
911d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
912d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
913d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
91498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
915d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
916d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
917e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
918d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
919d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
920d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
921d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
922d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
9235430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
924d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
9255430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
926d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
927d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
928d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
929d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
930d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
931d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
9325430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
933d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
934d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
9355430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
936d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
937d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
93874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
93974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            const int index = mIndex++;
94074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            // order isn't important, but we need to see both
94174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            if (index == 10) {
94274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
94374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else if (index == 11) {
94474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
94574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else { ADD_FAILURE(); }
94674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
947d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
948d3daa3198e2212c985c634821682d5819346b653Chris Craik
94906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 800, 800,
9508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
951eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
9526fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
9536fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
954eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
9556fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
9566fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
9576fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
9586fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
9596fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
9606fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
9616fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
9626fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9639cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800,
9649cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
9659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
9669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
9675854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
968f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
96974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(12, renderer.getIndex());
9706fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
9716fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9723a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
97306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev        auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
9748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
975eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
9766c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect);
977eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
9786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
9806fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
9816fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9826fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
9836fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
9846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
9859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
9869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
9879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
9889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
9896fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
9916fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
992f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
993b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
9946fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
9953a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
996b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
997b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
998b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
999b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
1000b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
10017435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
1002b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1003b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1004b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1005b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
1006b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
1007260ab726486317496bc12a57d599ea96dcde3284Mike Reed            ASSERT_EQ(SkBlendMode::kClear, PaintUtils::getBlendModeDirect(op.paint));
1008b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1009b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1010b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
1011b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
1012b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
1013b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
1014b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1015b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1016b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1017b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
1018b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
10197435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
1020b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1021b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1022b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1023b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
102406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1025b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1026eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
1027b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
1028b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1029b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
10309cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
10319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
10329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
10339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
10349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1035b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
1036f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1037b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
1038b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1039b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1040d5a90114128f4d3d528f1a0e93651496c968f940Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_round) {
1041d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase {
1042d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    public:
1043d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1044d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(0, mIndex++);
1045d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
1046d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik                    << "Bounds rect should round out";
1047d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        }
1048d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {}
1049d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {}
1050d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1051d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(1, mIndex++);
1052d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
1053d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik                    << "Bounds rect should round out";
1054d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        }
1055d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    };
1056d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
105706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1058d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1059d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
1060d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik                128, (SaveFlags::Flags)(0));
1061d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
1062d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik        canvas.restore();
1063d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    });
1064d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
1065d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
1066d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik            sLightGeometry, Caches::getInstance());
1067d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
1068d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
1069d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    SaveLayerUnclippedRoundTestRenderer renderer;
1070d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1071d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik    EXPECT_EQ(2, renderer.getIndex());
1072d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik}
1073d5a90114128f4d3d528f1a0e93651496c968f940Chris Craik
10743a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
1075b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
1076b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
1077b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1078b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1079b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
1080b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
1081b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
1082b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
1083b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
1084b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
1085b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
1086b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
1087b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
1088b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
1089b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
1090b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
1091b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1092b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1093b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
1094b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
1095b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
1096b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
1097b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
1098b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
1099b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
1100b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1101b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1102b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
1103b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1104b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1105b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
1106b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1107b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1108b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
110906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1110b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1111b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1112eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
1113b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
1114eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
1115eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
1116eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
1117eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
1118b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
1119b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
1120b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
11219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
11229cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
11239cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
11249cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
11259cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1126b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
1127f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1128b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
1129b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
1130b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1131b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
11323a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
11334876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
11344876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
11354876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
11364876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
11374876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11384876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
11394876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
11404876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
1141260ab726486317496bc12a57d599ea96dcde3284Mike Reed            EXPECT_EQ(SkBlendMode::kClear, PaintUtils::getBlendModeDirect(op.paint));
11424876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
11434876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
11444876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
11454876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
11464876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
11474876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11484876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
11494876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
11504876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11514876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
11524876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
11534876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
11544876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
11554876de16e34622634266d09522c9153c78c7c2fbChris Craik
115606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
11574876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
11584876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
11594876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
11604876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
11614876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
11624876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
11634876de16e34622634266d09522c9153c78c7c2fbChris Craik
11644876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
11659cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
11669cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
11679cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
11689cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
11694876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
11704876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
11714876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
11724876de16e34622634266d09522c9153c78c7c2fbChris Craik}
11734876de16e34622634266d09522c9153c78c7c2fbChris Craik
11743a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
117506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
11764876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
11774876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
11784876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
11794876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
11804876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
11814876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
11824876de16e34622634266d09522c9153c78c7c2fbChris Craik
11834876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
11849cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
11859cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
11869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
11879cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
11884876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
11894876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
11904876de16e34622634266d09522c9153c78c7c2fbChris Craik}
11914876de16e34622634266d09522c9153c78c7c2fbChris Craik
1192b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
1193b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
1194b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
1195b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
11963a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
1197b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
1198b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
1199b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
1200b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
1201b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
1202b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1203b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1204b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1205b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
1206b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1207b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1208b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1209b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
1210b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1211b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1212b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
1213b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
1214b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
1215b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
1216b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
1217b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1218b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1219b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1220b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
1221b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1222b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
1223b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
1224b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1225b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1226b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
1227b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1228b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1229b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
123074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1231b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1232b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
1233b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
1234b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
123574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
123674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(12, mIndex++);
123774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
123874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1239b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1240b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
124106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 600, 600, // 500x500 triggers clipping
1242b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1243eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
1244eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
1245eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
1246b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
1247b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1248b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1249b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1250b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
12519cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
12529cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600,
12539cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
12549cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
12559cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1256b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
1257f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
125874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(13, renderer.getIndex());
1259b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1260b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1261f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
1262d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
1263d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
126498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1265d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
126698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
126798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
126898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
1269d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1270d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1271d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
12720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1273d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
1274d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
1275d3daa3198e2212c985c634821682d5819346b653Chris Craik
1276e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
1277d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
1278d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1279d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1280d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
1281d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
128298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1283d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
1284d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1285d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1286d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
1287d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1288e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1289d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
1290d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1291d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
12920b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
129306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
129416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
129516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
12960b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
12970b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
12980b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
129916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
130098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
13010b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
130298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
130398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
130498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
13050b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13069cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(node);
13070b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
130998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
13100b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
13110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13129cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
13139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
13149cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
13159cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
13169cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
13170b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
1318f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
13190b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
13200b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13210b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
132298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
13230b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
13240b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1325f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
1326d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
1327d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
1328d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
1329d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
1330d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
1331d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
1332d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
1333d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1334d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
1335d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
1336d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
1337d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
133898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1339d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1340d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
1341d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
134298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
134398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
1344d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
1345d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
134698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
134798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
1348d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1349d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1350d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1351d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1352d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
1353d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
1354d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
1355d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
1356d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
1357d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1358d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1359d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1360d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1361d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1362d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
1363d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
136498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1365d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
1366d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1367d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
136898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
1369d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1370d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
137198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
137298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
1373d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
1374d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1375d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
137698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
137798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
1378d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1379d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1380e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1381d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
1382d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
138374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
138474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(13, mIndex++);
138574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1386d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1387d3daa3198e2212c985c634821682d5819346b653Chris Craik
138806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(50, 50, 150, 150,
138916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
139016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
13910b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
13920b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
13930b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
139416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
139598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
139698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
13970b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
13980b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
139906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
140016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
140116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
14020b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
14030b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
14040b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
14050b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1406eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
14070b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
14080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
140916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
141098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
141198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
14120b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14139cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
14140b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
141598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
14160b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
14170b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
14180b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14199cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
14209cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
14219cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
14229cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
14239cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
14240b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
1425f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
142674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(14, renderer.getIndex());
14270b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14280b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
14290b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
14300b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
14310b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
14320b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
14336246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14346246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, buildLayer) {
14356246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class BuildLayerTestRenderer : public TestRendererBase {
14366246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
14376246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
14386246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
14396246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
14406246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
14416246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
14426246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14436246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
14446246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
14456246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14466246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
14476246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Transform should be reset within layer";
14486246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14496246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
14506246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Damage rect should be used to clip layer content";
14516246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14526246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endLayer() override {
14536246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(2, mIndex++);
14546246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14556246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
14566246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
14576246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14586246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
14596246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
14606246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
14616246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
14626246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
146306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
14646246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
14656246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        props.mutateLayerProperties().setType(LayerType::RenderLayer);
1466260ab726486317496bc12a57d599ea96dcde3284Mike Reed        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
14676246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
14686246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
14696246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14706246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // create RenderNode's layer here in same way prepareTree would
14716246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
14726246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = &layer;
14736246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    TestUtils::syncHierarchyPropertiesAndDisplayList(node);
14756246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14766246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // only enqueue partial damage
14776246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
14786246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
14796246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14806246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // Draw, but pass empty node list, so no work is done for primary frame
14819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, sLightGeometry, Caches::getInstance());
14826246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    BuildLayerTestRenderer renderer;
14836246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
14846246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(3, renderer.getIndex());
14856246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
14866246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
14876246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = nullptr;
14886246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
14896246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
1490db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievnamespace {
1491db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
149206152cdd06da50762716cd455dcf7ab0117f25b0Stan Ilievstatic void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
1493161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
1494814ee6a9218aa339a4757b2c0ba1ad268f8dbc8aChris Craik    // order put in blue channel, transparent so overlapped content doesn't get rejected
1495814ee6a9218aa339a4757b2c0ba1ad268f8dbc8aChris Craik    paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
1496161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
1497161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
149806152cdd06da50762716cd455dcf7ab0117f25b0Stan Ilievstatic void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
149906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
15008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
1501161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
1502161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1503161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
1504161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
1505161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1506161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1507db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
1508db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievstatic void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder,
1509db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        std::function<void(RenderProperties& props, RecordingCanvas& canvas)> setup) {
1510db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
1511db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [expectedDrawOrder, setup](RenderProperties& props, RecordingCanvas& canvas) {
1512db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedRect(&canvas, expectedDrawOrder);
1513db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        if (setup) {
1514db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             setup(props, canvas);
1515d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1516db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    });
1517db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1518db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
1519db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
1520db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievclass ZReorderTestRenderer : public TestRendererBase {
1521db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievpublic:
1522db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    void onRectOp(const RectOp& op, const BakedOpState& state) override {
1523db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
1524db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
1525db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }
1526db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev};
1527db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
1528db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev} // end anonymous namespace
1529d3daa3198e2212c985c634821682d5819346b653Chris Craik
1530db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(FrameBuilder, zReorder) {
153106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
15328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1533347691f8d87157be0eaeca26f4003d8a06a275e3Stan Iliev        canvas.insertReorderBarrier(true);
1534347691f8d87157be0eaeca26f4003d8a06a275e3Stan Iliev        canvas.insertReorderBarrier(false);
1535161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1536161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
1537161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
1538161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
1539161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
1540161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
1541161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
1542161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
1543161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
1544161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
1545161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
1546161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
154788e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
154888e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedRect(&canvas, 11);
154988e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedNode(&canvas, 10, -1.0f);
155088e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(false);
155188e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true); //test with two empty reorder sections
155288e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true);
155388e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(false);
155488e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedRect(&canvas, 12);
1555161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
15569cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
15579cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
15589cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
15599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1560161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
1561f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
156288e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev    EXPECT_EQ(13, renderer.getIndex());
1563161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1564161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
15653a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
15668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
15678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
15688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
15698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
15708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
15718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
15728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
15738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
15748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
15758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
15768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
15778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
15788d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1579678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
15808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
15818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
15828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
15838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1584678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1585678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1586678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1587678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
15888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
15898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
15908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
15918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
15928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1593678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
15948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
15958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
15968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
15978d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1598678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
15998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
16008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
16018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
16028d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
16038d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
16048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
16058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
16068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
16078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
16088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
16098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
161006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
16118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
16128d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
16138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
16148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
16158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
16168d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
16178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
16188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
16198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
16208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
16218d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
162206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto projectingRipple = TestUtils::createNode<RecordingCanvas>(50, 0, 100, 50,
16238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
16248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
16258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
16268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
16278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
16288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
16298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
163006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(0, 50, 100, 100,
16318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
16328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
16338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
16348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
16358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
16368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
163706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
16388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1639678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1640678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1641678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1642eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
16438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
16448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
16458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
16468d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
16478d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
16488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
16499cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
16509cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
16519cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
16529cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
16538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1654f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
16558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
16568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
16578d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1658678ff81105753656aa4822f4f675ef96dc9d2b83Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
1659678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1660678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1661678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1662678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1663678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1664678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1665678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1666678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1667678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1668678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1669678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1670678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1671678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1672678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1673678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1674678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1675678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1676678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1677678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1678678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1679678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1680678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1681678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1682678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1683678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1684678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1685678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1686678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1687678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1688678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1689678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1690678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
169106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1692678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1693678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1694678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1695678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1696678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1697678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1698678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1699678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1700678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
170106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1702678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1703678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1704678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1705678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1706678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
170706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(100, 100, 300, 300,
1708678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1709678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1710678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1711678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1712678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
171306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1714678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1715678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1716678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1717678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1718678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1719678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1720678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1721678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1722678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1723678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1724678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1725678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1726678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1727678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1728678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1729678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1730678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
17319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
17329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1733678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1734678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
17359cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
17369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
17379cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
17389cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
17399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
17409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1741678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1742678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1743678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1744678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1745678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1746678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1747678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1748678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1749a748c08241e43fc68c7c34767d819aef5183936eChris CraikRENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
1750a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1751a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1752a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1753a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1754a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1755a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1756a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1757a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1758a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1759a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1760a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1761a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1762a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1763a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1764a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1765a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
176606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1767a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1768a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1769a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1770a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
177106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
1772a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1773a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1774a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1775a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1776a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1777a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1778a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1779a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1780a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
178106152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto child = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1782a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1783a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
17846c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
1785a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1786a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1787a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1788a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
178906152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
1790a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1791a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1792a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1793a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1794a748c08241e43fc68c7c34767d819aef5183936eChris Craik
17959cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
17969cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
17979cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
17989cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
1799a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1800a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1801a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1802a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1803a748c08241e43fc68c7c34767d819aef5183936eChris Craik
180498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
180598787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
180606152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    return TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
18078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
180816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
180916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
181098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
181198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
181298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
181398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
181498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
181598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
18166e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadow) {
1817d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1818d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1819d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1820d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
182198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
18226e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
18236e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
182498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
182598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
182698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
18276e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1828d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1829d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1830d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1831d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1832d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1833161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
183406152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
18358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
183698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
183798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1838d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
183998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
18409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
18419cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
18429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
18439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
184498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1845f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
184698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
184798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
184898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
18496e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
185098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
185198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
185298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
185398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
185498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
185598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
185698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
185798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
18586e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
18596e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
186098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
186198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
186298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
186398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
186498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
186598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
186698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
186798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
186898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
186998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
187074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
187174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(5, mIndex++);
187274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
187398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
187498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
187506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
18768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
187798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
187898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1879eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1880d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
188198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
188298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
188398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1884d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1885d3daa3198e2212c985c634821682d5819346b653Chris Craik
18869cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
18873a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
18889cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
18899cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
189098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1891f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
189274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(6, renderer.getIndex());
189398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1894d3daa3198e2212c985c634821682d5819346b653Chris Craik
1895f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
189698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
189798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
189898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
189998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
190098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
190198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
190298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
19036e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
19046e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
19056e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
190698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
190798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
190898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
190998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
191098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
191198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
191298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
191398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
191498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
191598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
191698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1917d3daa3198e2212c985c634821682d5819346b653Chris Craik
191806152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(50, 60, 150, 160,
191916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
192016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
192198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1922eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
192398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
192498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
192598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
192616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
192798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
192898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
192998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
193098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
193198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
193298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
193398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
193498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
193598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
19369cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(parent);
193798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
193898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
19399cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
19409cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
19413a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
19429cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferLayers(layerUpdateQueue);
19439cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
19449cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
194598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1946f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
194798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
194898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
194998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
195098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1951d3daa3198e2212c985c634821682d5819346b653Chris Craik}
195276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
19533a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
195498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
195598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
195698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
195798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
195898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
195998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
196098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
196198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
196298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
196398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
196498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
196506152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
19668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
196798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
196898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
196998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
197098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
19719cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
19723a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
19739cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
19749cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
197598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1976f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
197798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
197898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
197998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1980d645640180c25c2711e99aa82ec629155f8e91baChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowClipping) {
1981d645640180c25c2711e99aa82ec629155f8e91baChris Craik    class ShadowClippingTestRenderer : public TestRendererBase {
1982d645640180c25c2711e99aa82ec629155f8e91baChris Craik    public:
1983d645640180c25c2711e99aa82ec629155f8e91baChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1984d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(0, mIndex++);
1985d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipState->rect)
1986d645640180c25c2711e99aa82ec629155f8e91baChris Craik                    << "Shadow must respect pre-barrier canvas clip value.";
1987d645640180c25c2711e99aa82ec629155f8e91baChris Craik        }
1988d645640180c25c2711e99aa82ec629155f8e91baChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1989d645640180c25c2711e99aa82ec629155f8e91baChris Craik            EXPECT_EQ(1, mIndex++);
1990d645640180c25c2711e99aa82ec629155f8e91baChris Craik        }
1991d645640180c25c2711e99aa82ec629155f8e91baChris Craik    };
199206152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
1993d645640180c25c2711e99aa82ec629155f8e91baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1994d645640180c25c2711e99aa82ec629155f8e91baChris Craik        // Apply a clip before the reorder barrier/shadow casting child is drawn.
1995d645640180c25c2711e99aa82ec629155f8e91baChris Craik        // This clip must be applied to the shadow cast by the child.
19966c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect);
1997d645640180c25c2711e99aa82ec629155f8e91baChris Craik        canvas.insertReorderBarrier(true);
1998d645640180c25c2711e99aa82ec629155f8e91baChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1999d645640180c25c2711e99aa82ec629155f8e91baChris Craik    });
2000d645640180c25c2711e99aa82ec629155f8e91baChris Craik
20019cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2002d645640180c25c2711e99aa82ec629155f8e91baChris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
20039cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
20049cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
2005d645640180c25c2711e99aa82ec629155f8e91baChris Craik    ShadowClippingTestRenderer renderer;
2006d645640180c25c2711e99aa82ec629155f8e91baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2007d645640180c25c2711e99aa82ec629155f8e91baChris Craik    EXPECT_EQ(2, renderer.getIndex());
2008d645640180c25c2711e99aa82ec629155f8e91baChris Craik}
2009d645640180c25c2711e99aa82ec629155f8e91baChris Craik
201016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
201176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
2012d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
2013d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
2014d53e3bed1ca4a14b2a86d53eaef6969bd043176eChih-Hung Hsieh        explicit PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
2015d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
2016d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
2017d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
2018d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
2019d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
2020d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
2021d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
2022d3daa3198e2212c985c634821682d5819346b653Chris Craik
202306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
202416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
202516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
202676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
202776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
202876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
202916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
203076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20319cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
20329cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
20339cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
20349cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
203576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
2036f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
203776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
203876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
203976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20403a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
204176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
204276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
204376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
204476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
204576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
204676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
204776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
204876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20493a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
205076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
205176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
205276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
205376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
205476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
205576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
205676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
205776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
205876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20593a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
206076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
206176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
206276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
206376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
206476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
206576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
206676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
206776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
206876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
206976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20703a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
207176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
207276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
207376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
207476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
207576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
207676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
207776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
207876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
207976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
208076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
208176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
20823a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
208376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
208476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
208576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
208676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
208776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
208876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
208976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
209076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
209176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
209276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
209376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
209476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
209576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
209676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
209776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
209876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
209976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
210076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
210176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
210276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
210376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
210476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
210576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
210676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
210776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
210876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
210976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
211076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
211176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
211276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
211376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
2114161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
21158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
21168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
21178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
21188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
21198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
2120c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    Matrix4 drawLayerMatrix;
21218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
21228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
21238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
21248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
21258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
21268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
21278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
21288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
21298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
21308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
21318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
21328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
213316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
21348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
21358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
2136d53e3bed1ca4a14b2a86d53eaef6969bd043176eChih-Hung Hsieh        explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
21378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
21388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
21408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
21418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
21428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
21438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
21448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
21458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
21468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
21478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
21498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
21508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
21518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
21528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
21538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
21548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
21558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
2156c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck            mOutData->drawLayerMatrix = state.computedState.transform;
21578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
215874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
215974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
216074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
21618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
21628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
21638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
21648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
21668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
216706152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 10000, 10000,
216816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
21698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
21708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
21718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
217216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
217316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
217416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
217516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
217616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
21778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
21789cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
21799cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
21809cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
21819cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik                sLightGeometry, Caches::getInstance());
21829cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*syncedNode);
21838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
2185f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
21868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
218874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
21898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
21908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
21913a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
21928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
21938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
21948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
21958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
21968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
21978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
21988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
21995430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
22008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
22018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
22028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
22038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
22048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
2205c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    expected.loadTranslate(10, 0, 0);
2206c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck    EXPECT_MATRIX_APPROX_EQ(expected, observedData.drawLayerMatrix)
2207c9bb1a38d356087a4e5578307a6839eac0a1e6eeJohn Reck                << "expect drawLayer to be translated as part of being clipped";
22088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
22098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
22103a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
22118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
22128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
22138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
22148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
22158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
22168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
22178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
22188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
22198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
22208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
22218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
22228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
22238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
22248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
22255430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
22268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
22278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
22288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
22293a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
22308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
22318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
22328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
22338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
22348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
22358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
22368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
22378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
22388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
22395430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
22408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
22418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
22428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
224304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris CraikRENDERTHREAD_TEST(FrameBuilder, clip_replace) {
224404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    class ClipReplaceTestRenderer : public TestRendererBase {
224504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    public:
224604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
224704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(0, mIndex++);
224804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_TRUE(op.localClip->intersectWithRoot);
224904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(Rect(20, 10, 30, 40), state.computedState.clipState->rect)
225004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik                    << "Expect resolved clip to be intersection of viewport clip and clip op";
225104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        }
225204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    };
225306152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev    auto node = TestUtils::createNode<RecordingCanvas>(20, 20, 30, 30,
225404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
22556c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace);
2256260ab726486317496bc12a57d599ea96dcde3284Mike Reed        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
225704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    });
225804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
22599cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
22609cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik            sLightGeometry, Caches::getInstance());
22619cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
22629cd1bbe5c9e14472e631d8cc10005613925f34afChris Craik
226304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    ClipReplaceTestRenderer renderer;
226404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
226504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    EXPECT_EQ(1, renderer.getIndex());
226604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik}
226704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
2268db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderProjectedInMiddle) {
2269db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B
2270db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2271db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2272db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2273db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2274db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2275db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2276db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2277db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2278db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
2279db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2280db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2281db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2282db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2283db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2284db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2285db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2286db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2287db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2288db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2289db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2290db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2291db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2292db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2293db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2294db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2295db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2296db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2297db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2298db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderProjectLast) {
2299db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on E
2300db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  A
2301db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                / | \
2302db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /  |  \
2303db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C   E
2304db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2305db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2306db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2307db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2308db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2309db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0,  nullptr); //nodeB
2310db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2311db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 2
2312db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2313db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2314db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2315db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2316db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 3
2317db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2318db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeE
2319db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2320db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2321db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2322db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2323db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2324db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2325db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2326db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2327db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, renderer.getIndex());
2328db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2329db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2330db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderNoReceivable) {
2331db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected without receiver
2332db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2333db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2334db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2335db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2336db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2337db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2338db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2339db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2340db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
2341db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2342db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255,  [](RenderProperties& props, RecordingCanvas& canvas) {
2343db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //not having a projection receiver is an undefined behavior
2344db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2345db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2346db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2347db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2348db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2349db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2350db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2351db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2352db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2353db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2354db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2355db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2356db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, renderer.getIndex());
2357db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2358db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2359db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderParentReceivable) {
2360db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on C
2361db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2362db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2363db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2364db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
2365db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
2366db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2367db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2368db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2369db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
2370db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2371db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2372db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2373db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2374db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2375db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2376db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2377db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2378db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2379db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2380db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2381db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2382db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2383db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2384db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2385db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2386db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2387db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2388db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderSameNodeReceivable) {
2389db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2390db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2391db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
2392db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2393db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) {
2394db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //having a node that is projected on itself is an undefined/unexpected behavior
2395db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2396db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2397db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2398db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2399db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2400db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2401db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2402db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2403db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2404db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2405db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2406db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2407db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2408db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, renderer.getIndex());
2409db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2410db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2411db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderProjectedSibling) {
2412db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
2413db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
2414db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
2415db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B. R is not expected to be drawn (see Sibling2 outcome below),
2416db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev       but for some reason it is drawn.
2417db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2418db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /|\
2419db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              / | \
2420db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             B  C  R
2421db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2422db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2423db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2424db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
2425db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2426db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2427db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2428db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2429db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2430db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectBackwards(true);
2431db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setClipToBounds(false);
2432db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeR
2433db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2434db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2435db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2436db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2437db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2438db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2439db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2440db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2441db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2442db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2443db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2444db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderProjectedSibling2) {
2445db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
2446db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2447db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2448db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G
2449db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /|\
2450db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              / | \
2451db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             B  C  R
2452db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2453db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2454db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2455db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2456db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2457db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2458db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeB
2459db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2460db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeC
2461db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2462db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2463db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2464db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2465db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeG
2466db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2467db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2468db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2469db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2470db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2471db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2472db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2473db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2474db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2475db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2476db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2477db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderGrandparentReceivable) {
2478db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B
2479db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2480db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2481db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                B
2482db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2483db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                C
2484db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
2485db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                R
2486db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2487db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2488db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2489db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
2490db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2491db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
2492db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
2493db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setProjectBackwards(true);
2494db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setClipToBounds(false);
2495db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                } ); //nodeR
2496db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeC
2497db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2498db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2499db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2500db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2501db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2502db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2503db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2504db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2505db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2506db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, renderer.getIndex());
2507db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2508db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2509db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderTwoReceivables) {
2510db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, R is backward projected
2511db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2512db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2513db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2514db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
2515db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   R
2516db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2517db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2518db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2519db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2520db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2521db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2522db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2523db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2524db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2525db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
2526db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2527db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2528db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2529db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2530db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2531db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2532db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2533db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2534db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2535db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2536db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2537db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2538db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2539db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, renderer.getIndex());
2540db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2541db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2542db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
2543db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, G is backward projected
2544db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2545db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2546db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2547db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
2548db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   R
2549db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2550db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2551db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2552db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2553db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2554db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2555db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2556db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2557db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2558db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
2559db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
2560db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
2561db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2562db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
2563db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2564db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2565db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2566db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2567db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2568db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2569db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2570db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2571db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2572db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, renderer.getIndex());
2573db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2574db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2575db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
2576db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, R is backward projected
2577db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
2578db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
2579db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
2580db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
2581db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   D
2582db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    |
2583db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    R
2584db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
2585db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
2586db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, RecordingCanvas& canvas) {
2587db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
2588db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
2589db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
2590db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //C
2591db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //G
2592db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
2593db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
2594db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 4, [](RenderProperties& props, RecordingCanvas& canvas) { //D
2595db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
2596db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setProjectBackwards(true);
2597db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setClipToBounds(false);
2598db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                } ); //nodeR
2599db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeD
2600db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
2601db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
2602db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2603db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
2604db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            sLightGeometry, Caches::getInstance());
2605db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
2606db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
2607db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderTestRenderer renderer;
2608db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2609db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(5, renderer.getIndex());
2610db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
2611db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
26126fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
26136fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
2614