FrameBuilderTests.cpp revision aafb01d8ade0def3f51b74ae3bbc610c4ab33044
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
328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikconst LayerUpdateQueue sEmptyLayerUpdateQueue;
336e068c0182f6f85bccb855a647510724d1c65a13Chris Craikconst FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
346e068c0182f6f85bccb855a647510724d1c65a13Chris Craik
3598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik/**
375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual class implemented by each test to redirect static operation / state transitions to
385854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * virtual methods.
396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
415854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * and allows Renderer vs Dispatching behavior to be merged.
426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * onXXXOp methods fail by default - tests should override ops they expect
44d3daa3198e2212c985c634821682d5819346b653Chris Craik * startRepaintLayer fails by default - tests should override if expected
456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * startFrame/endFrame do nothing by default - tests should override to intercept
466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik */
475854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestRendererBase {
486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikpublic:
495854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    virtual ~TestRendererBase() {}
50d3daa3198e2212c985c634821682d5819346b653Chris Craik    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
51a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer creation not expected in this test";
52a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        return nullptr;
53a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
55a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer repaint not expected in this test";
56a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
57a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void endLayer() {
58a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer updates not expected in this test";
59a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
6098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
61e4db79de127cfe961195f52907af8451026eaa20Chris Craik    virtual void endFrame(const Rect& repaintRect) {}
625854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
6315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for single draw methods
6415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
65a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void on##Type(const Type&, const BakedOpState&) { \
66a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << #Type " not expected in this test"; \
67a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
687cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X)
6915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
7115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for merged draw methods
7215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
7515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
767cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X)
7715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
795854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int getIndex() { return mIndex; }
805854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
815854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikprotected:
825854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int mIndex = 0;
835854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik};
846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
855854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik/**
865854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Dispatches all static methods to similar formed methods on renderer, which fail by default but
878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * are overridden by subclasses per test.
885854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik */
895854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestDispatcher {
905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikpublic:
9115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define single op methods, which redirect to TestRendererBase
9215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
935854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
945854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik        renderer.on##Type(op, state); \
956fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
967cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X);
9715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
9815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
9915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define merged op methods, which redirect to TestRendererBase
10015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
10115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
10215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        renderer.onMerged##Type##s(opList); \
10315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
1047cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X);
10515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
1066fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik};
107b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1085854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass FailRenderer : public TestRendererBase {};
1096fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1103a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simple) {
111d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleTestRenderer : public TestRendererBase {
112d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
11398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
114d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
115d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(100u, width);
116d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(200u, height);
117d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
118d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
119d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
120d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
121d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
122d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
123d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
124e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
125d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
126d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
127d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
128d3daa3198e2212c985c634821682d5819346b653Chris Craik
1298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
1308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
131ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
132b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawBitmap(bitmap, 10, 10, nullptr);
134b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
135f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1363a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
1375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleTestRenderer renderer;
138f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
1406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
1416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1423a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
143386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    class SimpleStrokeTestRenderer : public TestRendererBase {
144386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    public:
145386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
146386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(0, mIndex++);
147386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            // even though initial bounds are empty...
148386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_TRUE(op.unmappedBounds.isEmpty())
149386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "initial bounds should be empty, since they're unstroked";
150386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
151386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "final bounds should account for stroke";
152386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        }
153386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    };
154386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
155386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
156386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
157386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        SkPaint strokedPaint;
158386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        strokedPaint.setStrokeWidth(10);
159386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        canvas.drawPoint(50, 50, strokedPaint);
160386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    });
161f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1623a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
163386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    SimpleStrokeTestRenderer renderer;
164f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
165386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    EXPECT_EQ(1, renderer.getIndex());
166386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik}
167386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
1683a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
1698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
171eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
1726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
1736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
1756fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
176f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
1773a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
178b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1795854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
180f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
181b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
182b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1833a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
184a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
185d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleBatchingTestRenderer : public TestRendererBase {
186d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
187d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
188a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
189d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
190d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
191a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
192d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
193d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
194d3daa3198e2212c985c634821682d5819346b653Chris Craik
1958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
19715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
19815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
199b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
200b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
201b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
202eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
203a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
204b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
206b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawBitmap(bitmap, 5, 0, nullptr);
207b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
208b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
209b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
210b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
211f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
2123a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
2135854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
214f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
215a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
21615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
217a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
218a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
2193a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
22093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
22193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
22293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
22393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
22493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
22593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
22693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
22793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
22893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
22993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
23093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
23193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    auto node = TestUtils::createNode(0, 0, 100, 100,
23293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
23393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
23493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
23693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
23793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 0, 40, nullptr);
23893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
24093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
24193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 0, nullptr);
24293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
24493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
24593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 80, 40, nullptr);
24693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
24893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
24993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 70, nullptr);
25093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
25193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
252f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
2533a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
25493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
255f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
25693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
25793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
25893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
2593a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textMerging) {
260d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
261d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
262d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
263d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
264d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
265d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
266d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
267d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
268d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
269d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
270d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
271d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
272d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            [](RenderProperties& props, TestCanvas& canvas) {
273d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
274d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
275d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
276d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
277dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
278dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
279d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
280f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
2813a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
282d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
283f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
284d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
285d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
286d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
2873a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
288a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
289a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
290a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
291a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
292a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
293a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
29415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
29515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
29615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
29715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
298a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
299a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
3008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 2000,
3018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
302a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
303a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
304a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
305a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setStrikeThruText(true);
30642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
307a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
308dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
309a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
310a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
311f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
3123a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
313a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
314f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
315a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
316d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
317b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
318b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
3197c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craikstatic auto styles = {
3207c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
3217c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3223a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStyle) {
3237c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    class TextStyleTestRenderer : public TestRendererBase {
3247c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    public:
3257c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
3267c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(0, mIndex);
3277c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(3u, opList.count);
3287c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            mIndex += opList.count;
3297c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3307c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            int index = 0;
3317c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            for (auto style : styles) {
3327c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                auto state = opList.states[index++];
3337c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(style, state->op->paint->getStyle())
3347c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Remainder of validation relies upon stable merged order";
3357c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(0, state->computedState.clipSideFlags)
3367c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Clipped bounds validation requires unclipped ops";
3377c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            }
3387c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3397c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect fill = opList.states[0]->computedState.clippedBounds;
3407c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect stroke = opList.states[1]->computedState.clippedBounds;
3417c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
3427c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                    << "Stroke+Fill should be same as stroke";
3437c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3447c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_TRUE(stroke.contains(fill));
3457c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_FALSE(fill.contains(stroke));
3467c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
34779abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            // outset by half the stroke width
3487c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect outsetFill(fill);
34979abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            outsetFill.outset(5);
3507c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, outsetFill);
3517c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
3527c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    };
3537c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
3547c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
3557c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint paint;
3567c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
3577c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setAntiAlias(true);
3587c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextSize(50);
3597c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setStrokeWidth(10);
3607c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3617c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // draw 3 copies of the same text overlapping, each with a different style.
3627c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // They'll get merged, but with
3637c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        for (auto style : styles) {
3647c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            paint.setStyle(style);
365dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
3667c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
3677c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    });
3687c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
3693a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
3707c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    TextStyleTestRenderer renderer;
3717c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3727c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
3737c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik}
3747c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
375aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
376aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
377d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
378d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
379d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
380e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
381d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
382d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
383d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
384d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
385d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
386d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
387d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
388d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
389d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
390243e85b2e443def1ef47a180e824b36f513c8db8Chris Craik            SkMatrix::MakeTrans(5, 5));
391d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
392d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
393d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
394eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
395d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
396d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
397d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
398d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
399f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4003a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
401aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerClipLocalMatrixTestRenderer renderer;
402f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
403d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
404d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
405d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
406aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
407aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
408aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    public:
409aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
410aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_EQ(0, mIndex++);
411aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
412aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            Matrix4 expected;
413aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            expected.loadTranslate(35, 45, 0);
414aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
415aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        }
416aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    };
417aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
418aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
419aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
420aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
421aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
422aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
423aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.save(SaveFlags::MatrixClip);
424aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.translate(30, 40);
425aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
426aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.restore();
427aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
428aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
429aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
430aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
431aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerCombineMatricesTestRenderer renderer;
432aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
433aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    EXPECT_EQ(1, renderer.getIndex());
434aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
435aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
436aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
437aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
438aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
439aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
440aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
441aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
442aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
443aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
444aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
445aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
446aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
447aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FailRenderer renderer;
448aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
449aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
450aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
4513a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, functor_reject) {
452223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
453223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
454223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
455223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
456223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
457223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
458223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
459223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
460223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
461223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
462223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
463223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
464223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.callDrawGLFunction(&noopFunctor);
465223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
466223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
467223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4683a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(scrolledFunctorView),
4693a5811b50157e7ba50854caf957e806aee794d39Chris Craik            sLightGeometry, Caches::getInstance());
470223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
471223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
472223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
473223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
474223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
475a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikRENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
476a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    class ColorTestRenderer : public TestRendererBase {
477a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    public:
478a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
479a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(0, mIndex++);
480a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
481a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik                    << "Color op should be expanded to bounds of surrounding";
482a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        }
483a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    };
484a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
485a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
486a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
487a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        props.setClipToBounds(false);
488a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
489a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    });
490a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
491a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
492a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            TestUtils::createSyncedNodeList(unclippedColorView),
493a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            sLightGeometry, Caches::getInstance());
494a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    ColorTestRenderer renderer;
495a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
496a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
497a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik}
498a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
499a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikTEST(FrameBuilder, renderNode) {
500d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
501d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
502d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
503d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
504d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
5055430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
506d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
507d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
508d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
509d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
510d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
511d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
512d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
513d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
514d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
515d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
516d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
517d3daa3198e2212c985c634821682d5819346b653Chris Craik
5188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(10, 10, 110, 110,
5198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
520b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
521b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
522b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
523b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
524b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
5258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
526d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
527ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
528ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
529ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
530ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
531eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
532ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
533d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
534ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
535b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
536b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
537f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5383a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
5395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
540f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
541223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
542b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
543b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
5443a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clipped) {
545d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
546d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
547d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
548d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
549d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
550e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
551d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
552d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
553d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
554d3daa3198e2212c985c634821682d5819346b653Chris Craik
5558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
5568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
557ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
558ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawBitmap(bitmap, 0, 0, nullptr);
559ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
560ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
561f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
5620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
5633a5811b50157e7ba50854caf957e806aee794d39Chris Craik            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
5645854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
565f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
566ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
567ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
5683a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
569d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
570d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
571d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
572d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
573d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
574d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
575d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
576d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
577d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
578d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
579d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
580d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
581d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
582d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
5835430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
584e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
585d3daa3198e2212c985c634821682d5819346b653Chris Craik
586d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
587d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
588d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
589d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
590d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
591d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
592d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
593e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
594d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
595d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
596d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
597d3daa3198e2212c985c634821682d5819346b653Chris Craik
5988d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
5998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
600eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
6016fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
6026fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6036fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
604f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6053a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
6065854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
607f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
6085854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex());
609b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
6106fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6113a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
612d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
613d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
614d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
615d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
616d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
617d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
618d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
619d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
620d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
621d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
622d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
623d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
624d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
625d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
626d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
627d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
628d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
629d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
630d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
631d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
632d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
633d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
634d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
635d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
63698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
637d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
638d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
639e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
640d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
641d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
642d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
643d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
644d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
6455430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
646d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
6475430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
648d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
649d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
650d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
651d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
652d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
653d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
6545430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
655d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
656d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
6575430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
658d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
659d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
660d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
661d3daa3198e2212c985c634821682d5819346b653Chris Craik
6628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 800, 800,
6638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
664eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
6656fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
6666fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
667eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
6686fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
6696fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
6706fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
6716fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
6726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
6736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
6756fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
676f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
6773a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
6785854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
679f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
6805854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(10, renderer.getIndex());
6816fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
6826fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6833a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
6848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        auto node = TestUtils::createNode(0, 0, 200, 200,
6858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
686eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
6876fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
688eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
6896fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6906fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
6916fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
6926fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6936fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6946fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6956fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
696f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6973a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
6986fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6995854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
7006fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
701f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
702b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
7036fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
7043a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
705b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
706b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
707b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
708b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
709b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
7107435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
711b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
712b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
713b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
714b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
715b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
716b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
717b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
718b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
719b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
720b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
721b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
722b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
723b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
724b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
725b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
726b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
727b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
7287435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
729b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
730b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
731b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
732b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
733b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
734b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
735eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
736b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
737b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
738b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
739f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
7403a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
741b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
742f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
743b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
744b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
745b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
7463a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
747b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
748b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
749b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
750b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
751b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
752b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
753b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
754b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
755b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
756b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
757b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
758b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
759b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
760b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
761b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
762b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
763b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
764b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
765b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
766b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
767b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
768b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
769b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
770b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
771b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
772b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
773b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
774b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
775b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
776b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
777b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
778b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
779b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
780b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
781b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
782b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
783b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
784eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
785b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
786eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
787eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
788eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
789eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
790b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
791b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
792b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
793f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
7943a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
795b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
796f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
797b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
798b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
799b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
800b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
8013a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
8024876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
8034876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
8044876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
8054876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
8064876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
8074876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
8084876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
8094876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
8104876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
8114876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
8124876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
8134876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
8144876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
8154876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
8164876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
8174876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
8184876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
8194876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
8204876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
8214876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
8224876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
8234876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
8244876de16e34622634266d09522c9153c78c7c2fbChris Craik
8254876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
8264876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
8274876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
8284876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
8294876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
8304876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
8314876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
8324876de16e34622634266d09522c9153c78c7c2fbChris Craik
8334876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
8344876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
8353a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
8364876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
8374876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
8384876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
8394876de16e34622634266d09522c9153c78c7c2fbChris Craik}
8404876de16e34622634266d09522c9153c78c7c2fbChris Craik
8413a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
8424876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
8434876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
8444876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
8454876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
8464876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
8474876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
8484876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
8494876de16e34622634266d09522c9153c78c7c2fbChris Craik
8504876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
8514876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
8523a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
8534876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
8544876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
8554876de16e34622634266d09522c9153c78c7c2fbChris Craik}
8564876de16e34622634266d09522c9153c78c7c2fbChris Craik
857b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
858b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
859b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
860b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
8613a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
862b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
863b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
864b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
865b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
866b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
867b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
868b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
869b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
870b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
871b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
872b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
873b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
874b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
875b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
876b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
877b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
878b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
879b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
880b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
881b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
882b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
883b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
884b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
885b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
886b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
887b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
888b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
889b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
890b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
891b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
892b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
893b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
894b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
895b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
896b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
897b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
898b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
899b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
900b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
901b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
902b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
903eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
904eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
905eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
906b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
907b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
908b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
909b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
910b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
911f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
9123a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
913b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
914f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
915b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(12, renderer.getIndex());
916b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
917b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
918f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
919d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
920d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
92198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
922d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
92398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
92498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
92598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
926d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
927d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
928d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
9290b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
930d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
931d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
932d3daa3198e2212c985c634821682d5819346b653Chris Craik
933e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
934d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
935d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
936d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
937d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
938d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
93998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
940d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
941d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
942d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
943d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
944d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
945e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
946d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
947d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
948d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
9490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
95116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
95216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
9530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
9540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
9550b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
95616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
95798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
9580b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
95998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
96098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
96198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
9620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9637db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
9640b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9650b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
96698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
9670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
9680b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
969f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
9703a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedNodeList, sLightGeometry, Caches::getInstance());
9710b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
972f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
9730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
9740b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
97698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
9770b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
9780b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
979f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
980d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
981d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
982d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
983d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
984d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
985d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
986d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
987d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
988d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
989d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
990d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
991d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
99298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
993d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
994d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
995d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
99698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
99798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
998d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
999d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
100098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
100198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
1002d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1003d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1004d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1005d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1006d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
1007d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
1008d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
1009d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
1010d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
1011d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1012d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1013d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1014d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1015d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1016d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
1017d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
101898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1019d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
1020d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1021d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
102298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
1023d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1024d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
102598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
102698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
1027d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
1028d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1029d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
103098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
103198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
1032d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1033d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1034e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1035d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
1036d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1037d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1038d3daa3198e2212c985c634821682d5819346b653Chris Craik
103916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto child = TestUtils::createNode(50, 50, 150, 150,
104016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
104116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
10420b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
10430b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
10440b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
104516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
104698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
104798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
10480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
10490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
105016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 200, 200,
105116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
105216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
10530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
10540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
10550b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
10560b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1057eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
10580b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
10590b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
106016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
106198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
106298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
10630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
10647db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
10650b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
106698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
10670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
10680b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
10690b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1070f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
10713a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedList, sLightGeometry, Caches::getInstance());
10720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
1073f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
10740b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(13, renderer.getIndex());
10750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
10760b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
10770b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
10780b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
10790b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
10800b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1081161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
1082161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
1083161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
1084161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
1085161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1086161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
108716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
10888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
1089161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
1090161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1091161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
1092161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
1093161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1094161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
10953a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, zReorder) {
1096d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ZReorderTestRenderer : public TestRendererBase {
1097d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1098d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1099d3daa3198e2212c985c634821682d5819346b653Chris Craik            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
1100d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
1101d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1102d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1103d3daa3198e2212c985c634821682d5819346b653Chris Craik
110416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 100, 100,
11058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1106161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1107161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
1108161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
1109161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
1110161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
1111161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
1112161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
1113161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
1114161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
1115161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
1116161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
1117161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
1118161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1119f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
11203a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
1121161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
1122f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1123161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    EXPECT_EQ(10, renderer.getIndex());
1124161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1125161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
11263a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
11278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
11288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
11298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
11308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
11318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
11328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
11338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
11348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
11358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
11368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
11378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
11388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
11398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1140678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
11418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
11428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
11438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
11448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1145678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1146678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1147678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1148678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
11498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
11508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
11518d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
11528d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
11538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1154678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
11558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
11568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
11578d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
11588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1159678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
11608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
11618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
11628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
11638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
11648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
11658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
11668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
11678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
11688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
11698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
11708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
11718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
11728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
11738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
11748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
11758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
11768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
11778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
11788d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
11798d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
11818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
11828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
11848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
11858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
11868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
11878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
11898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
11908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(0, 50, 100, 100,
11928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
11938d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
11958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
11968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
11978d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11988d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
11998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1200678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1201678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1202678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1203eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
12048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
12058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
12068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
12078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
12088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
12098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1210f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
12113a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
12128d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1213f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
12148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
12158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
12168d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1217678ff81105753656aa4822f4f675ef96dc9d2b83Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
1218678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1219678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1220678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1221678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1222678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1223678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1224678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1225678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1226678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1227678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1228678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1229678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1230678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1231678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1232678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1233678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1234678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1235678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1236678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1237678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1238678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1239678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1240678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1241678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1242678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1243678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1244678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1245678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1246678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1247678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1248678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1249678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
1250678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1251678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1252678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1253678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1254678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1255678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1256678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1257678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1258678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1259678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1260678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1261678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1262678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1263678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1264678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1265678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1266678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto child = TestUtils::createNode(100, 100, 300, 300,
1267678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1268678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1269678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1270678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1271678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1272678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1273678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1274678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1275678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1276678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1277678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1278678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1279678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1280678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1281678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1282678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1283678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1284678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1285678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1286678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1287678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1288678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1289678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1290678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto syncedList = TestUtils::createSyncedNodeList(parent);
1291678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1292678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
1293678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
12943a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedList, sLightGeometry, Caches::getInstance());
1295678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1296678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1297678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1298678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1299678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1300678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1301678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1302678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1303a748c08241e43fc68c7c34767d819aef5183936eChris CraikRENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
1304a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1305a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1306a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1307a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1308a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1309a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1310a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1311a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1312a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1313a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1314a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1315a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1316a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1317a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1318a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1319a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
1320a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1321a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1322a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1323a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1324a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1325a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1326a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1327a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1328a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1329a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1330a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1331a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1332a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1333a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1334a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1335a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto child = TestUtils::createNode(0, 0, 400, 400,
1336a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1337a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
1338a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
1339a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1340a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1341a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1342a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1343a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1344a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1345a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1346a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1347a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1348a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1349a748c08241e43fc68c7c34767d819aef5183936eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
13503a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
1351a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1352a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1353a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1354a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1355a748c08241e43fc68c7c34767d819aef5183936eChris Craik
135698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
135798787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
135816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return TestUtils::createNode(0, 0, 100, 100,
13598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
136016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
136116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
136298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
136398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
136498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
136598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
136698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
136798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13686e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadow) {
1369d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1370d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1371d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1372d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
137398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
13746e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
13756e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
137698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
137798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
137898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
13796e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1380d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1381d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1382d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1383d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1384d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1385161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
13868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
13878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
138898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
138998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1390d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
139198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1392f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13933a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
139498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1395f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
139698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
139798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
139898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13996e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
140098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
140198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
140298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
140398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
140498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
140598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
140698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
140798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
14086e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
14096e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
141098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
141198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
141298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
141398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
141498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
141598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
141698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
141798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
141898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
141998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
142098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
142198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
14228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
14238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
142498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
142598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1426eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1427d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
142898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
142998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
143098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1431d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1432d3daa3198e2212c985c634821682d5819346b653Chris Craik
1433f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
14346e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
14353a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
143698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1437f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
143898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
143998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1440d3daa3198e2212c985c634821682d5819346b653Chris Craik
1441f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
144298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
144398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
144498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
144598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
144698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
144798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
144898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
14496e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
14506e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
14516e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
145298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
145398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
145498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
145598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
145698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
145798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
145898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
145998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
146098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
146198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
146298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1463d3daa3198e2212c985c634821682d5819346b653Chris Craik
14648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(50, 60, 150, 160,
146516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
146616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
146798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1468eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
146998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
147098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
147198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
147216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
147398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
147498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
147598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
147698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
147798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
147898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
147998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
148098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
148198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
14827db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
148398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
148498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
1485f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
14866e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedList,
14873a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
148898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1489f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
149098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
149198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
149298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
149398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1494d3daa3198e2212c985c634821682d5819346b653Chris Craik}
149576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
14963a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
149798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
149898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
149998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
150098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
150198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
150298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
150398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
150498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
150598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
150698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
150798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
15088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
15098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
151098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
151198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
151298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
151398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
151498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1515f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
15166e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
15173a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
151898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1519f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
152098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
152198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
152298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
152316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
152476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
1525d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
1526d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1527d3daa3198e2212c985c634821682d5819346b653Chris Craik        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1528d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
1529d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1530d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
1531d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
1532d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1533d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1534d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1535d3daa3198e2212c985c634821682d5819346b653Chris Craik
153616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
153716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
153816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
153976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
154076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
154176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
154216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
154376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1544f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
15453a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
154676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
1547f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
154876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
154976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
155076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15513a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
155276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
155376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
155476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
155576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
155676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
155776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
155876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
155976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15603a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
156176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
156276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
156376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
156476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
156576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
156676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
156776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
156876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
156976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15703a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
157176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
157276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
157376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
157476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
157576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
157676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
157776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
157876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
157976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
158076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15813a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
158276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
158376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
158476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
158576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
158676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
158776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
158876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
158976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
159076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
159176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
159276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
15933a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
159476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
159576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
159676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
159776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
159876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
159976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
160076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
160176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
160276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
160376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
160476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
160576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
160676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
160776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
160876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
160976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
161076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
161176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
161276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
161376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
161476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
161576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
161676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
161776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
161876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
161976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
162076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
162176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
162276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
162376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
162476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
1625161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
16268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
16278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
16288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
16298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
16308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
16318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
16328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
16338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
16348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
16358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
16368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
16378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
16388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
16398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
16408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
16418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
16428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
164316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
16448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
16458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
16468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
16478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
16488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
16508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
16518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
16528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
16538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
16548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
16558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
16568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
16578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
16598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
16608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
16618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
16628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
16638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
16648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
16658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
16668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
16678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
16688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
16698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
16708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
16728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
167316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 10000, 10000,
167416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
16758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
16768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
16778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
167816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
167916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
168016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
168116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
168216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
16838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16847db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
16858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16866e068c0182f6f85bccb855a647510724d1c65a13Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
16873a5811b50157e7ba50854caf957e806aee794d39Chris Craik            nodes, sLightGeometry, Caches::getInstance());
16888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
1689f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
16908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
16928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
16938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16953a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
16968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
16998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
17008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
17018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
17028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
17035430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
17048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
17058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
17068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
17078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
17088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
17098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
17108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
17113a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
17128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
17138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
17148ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
17158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
17168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
17178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
17188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
17198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
17208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
17218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
17228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
17238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
17248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
17258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
17265430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
17278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
17288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
17298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
17303a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
17318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
17328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
17338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
17348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
17358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
17368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
17378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
17388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
17398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
17405430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
17418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
17428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
17438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
17446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
17456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
1746