FrameBuilderTests.cpp revision 7db5ffb7dbd30202468459e2ef4426e91d4fcbb3
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;
338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikconst Vector3 sLightCenter = {100, 100, 100};
3498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
356fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik/**
365854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual class implemented by each test to redirect static operation / state transitions to
375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * virtual methods.
386fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * and allows Renderer vs Dispatching behavior to be merged.
416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * onXXXOp methods fail by default - tests should override ops they expect
43d3daa3198e2212c985c634821682d5819346b653Chris Craik * startRepaintLayer fails by default - tests should override if expected
446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * startFrame/endFrame do nothing by default - tests should override to intercept
456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik */
465854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestRendererBase {
476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikpublic:
485854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    virtual ~TestRendererBase() {}
49d3daa3198e2212c985c634821682d5819346b653Chris Craik    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
50a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer creation not expected in this test";
51a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        return nullptr;
52a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
54a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer repaint not expected in this test";
55a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
56a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void endLayer() {
57a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer updates not expected in this test";
58a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
60e4db79de127cfe961195f52907af8451026eaa20Chris Craik    virtual void endFrame(const Rect& repaintRect) {}
615854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
6215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for single draw methods
6315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
64a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void on##Type(const Type&, const BakedOpState&) { \
65a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << #Type " not expected in this test"; \
66a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
677cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X)
6815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
6915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
7015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for merged draw methods
7115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
7215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
757cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X)
7615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
785854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int getIndex() { return mIndex; }
795854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
805854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikprotected:
815854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int mIndex = 0;
825854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik};
836fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
845854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik/**
855854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Dispatches all static methods to similar formed methods on renderer, which fail by default but
868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * are overridden by subclasses per test.
875854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik */
885854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestDispatcher {
895854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikpublic:
9015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define single op methods, which redirect to TestRendererBase
9115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
925854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
935854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik        renderer.on##Type(op, state); \
946fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
957cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X);
9615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
9715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
9815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define merged op methods, which redirect to TestRendererBase
9915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
10015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
10115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        renderer.onMerged##Type##s(opList); \
10215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
1037cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X);
10415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
1056fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik};
106b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1075854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass FailRenderer : public TestRendererBase {};
1086fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
109f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simple) {
110d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleTestRenderer : public TestRendererBase {
111d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
11298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
113d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
114d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(100u, width);
115d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(200u, height);
116d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
117d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
118d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
119d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
120d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
121d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
122d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
123e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
124d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
125d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
126d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
127d3daa3198e2212c985c634821682d5819346b653Chris Craik
1288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
1298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
130ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
131b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
132b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawBitmap(bitmap, 10, 10, nullptr);
133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
134f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1357db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
1365854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleTestRenderer renderer;
137f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1385854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
1396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
1406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
141f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simpleStroke) {
142386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    class SimpleStrokeTestRenderer : public TestRendererBase {
143386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    public:
144386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
145386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(0, mIndex++);
146386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            // even though initial bounds are empty...
147386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_TRUE(op.unmappedBounds.isEmpty())
148386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "initial bounds should be empty, since they're unstroked";
149386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
150386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "final bounds should account for stroke";
151386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        }
152386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    };
153386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
154386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
155386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
156386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        SkPaint strokedPaint;
157386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        strokedPaint.setStrokeWidth(10);
158386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        canvas.drawPoint(50, 50, strokedPaint);
159386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    });
160f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1617db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
162386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    SimpleStrokeTestRenderer renderer;
163f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
164386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    EXPECT_EQ(1, renderer.getIndex());
165386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik}
166386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
167f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simpleRejection) {
1688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1706fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
1716fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
1726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
1746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
175f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
1767db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
177b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1785854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
179f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
180b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
181b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
182f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simpleBatching) {
183a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
184d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleBatchingTestRenderer : public TestRendererBase {
185d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
186d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
187a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
188d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
189d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
190a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
191d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
192d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
193d3daa3198e2212c985c634821682d5819346b653Chris Craik
1948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
19615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
19715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
198b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
199b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
200b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
201b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
202a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
203b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
204b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawBitmap(bitmap, 5, 0, nullptr);
206b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
207b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
208b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
209b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
210f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
2117db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
2125854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
213f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
214a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
21515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
216a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
217a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
218f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, clippedMerging) {
21993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
22093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
22193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
22293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
22393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
22493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
22593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
22693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
22793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
22893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
22993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
23093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    auto node = TestUtils::createNode(0, 0, 100, 100,
23193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
23293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
23393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
23593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
23693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 0, 40, nullptr);
23793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
23993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
24093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 0, nullptr);
24193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
24393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
24493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 80, 40, nullptr);
24593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
24793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
24893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 70, nullptr);
24993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
25093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
251f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
2527db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
25393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
254f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
25593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
25693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
25793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
258f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, textMerging) {
259d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
260d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
261d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
262d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
263d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
264d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
265d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
266d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
267d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
268d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
269d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
270d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
271d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            [](RenderProperties& props, TestCanvas& canvas) {
272d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
273d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
274d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
275d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
276d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
277d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
278d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
279f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
2807db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
281d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
282f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
283d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
284d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
285d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
286f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, textStrikethrough) {
287a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
288a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
289a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
290a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
291a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
292a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
29315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
29415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
29515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
29615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
297a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
298a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
2998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 2000,
3008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
301a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
302a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
303a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
304a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setStrikeThruText(true);
30542a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
306a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
307a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            TestUtils::drawTextToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
308a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
309a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
310f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
3117db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
312a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
313f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
314a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
315d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
316b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
317b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
318f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer) {
319d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    class TextureLayerTestRenderer : public TestRendererBase {
320d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
321d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
322d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
323e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
324d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
325d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
326d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
327d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
328d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
329d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
330d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
331d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
332d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
333d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [](Matrix4* transform) {
334d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        transform->loadTranslate(5, 5, 0);
335d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
336d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
337d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
338d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
339d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.save(SkCanvas::kMatrixClip_SaveFlag);
340d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
341d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
342d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
343d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
344f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
3457db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
346d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    TextureLayerTestRenderer renderer;
347f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
348d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
349d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
350d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
351f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderNode) {
352d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
353d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
354d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
355d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
356d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
3575430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
358d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
359d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
360d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
361d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
362d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
363d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
364d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
365d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
366d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
367d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
368d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
369d3daa3198e2212c985c634821682d5819346b653Chris Craik
3708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(10, 10, 110, 110,
3718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
372b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
373b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
374b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
375b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
376b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
3778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
378d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
379ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
380ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
381ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
382ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
383ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
384ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
385d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
386ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
387b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
388b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
389f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
3907db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(parent), sLightCenter);
3915854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
392f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
393b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
394b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
395f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, clipped) {
396d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
397d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
398d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
399d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
400d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
401e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
402d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
403d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
404d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
405d3daa3198e2212c985c634821682d5819346b653Chris Craik
4068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
4078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
408ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
409ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawBitmap(bitmap, 0, 0, nullptr);
410ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
411ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
412f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
4130b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
4147db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            200, 200, TestUtils::createSyncedNodeList(node), sLightCenter);
4155854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
416f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
417ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
418ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
419f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_simple) {
420d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
421d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
422d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
423d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
424d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
425d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
426d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
427d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
428d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
429d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
430d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
431d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
432d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
433d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
4345430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
435e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
436d3daa3198e2212c985c634821682d5819346b653Chris Craik
437d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
438d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
439d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
440d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
441d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
442d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
443d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
444e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
445d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
446d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
447d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
448d3daa3198e2212c985c634821682d5819346b653Chris Craik
4498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
4508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
4516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SkCanvas::kClipToLayer_SaveFlag);
4526fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
4536fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
4546fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
455f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4567db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
4575854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
458f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
4595854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex());
460b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
4616fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
462f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_nested) {
463d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
464d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
465d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
466d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
467d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
468d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
469d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
470d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
471d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
472d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
473d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
474d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
475d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
476d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
477d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
478d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
479d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
480d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
481d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
482d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
483d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
484d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
485d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
486d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
48798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
488d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
489d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
490e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
491d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
492d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
493d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
494d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
495d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
4965430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
497d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
4985430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
499d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
500d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
501d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
502d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
503d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
504d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
5055430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
506d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
507d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
5085430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
509d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
510d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
511d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
512d3daa3198e2212c985c634821682d5819346b653Chris Craik
5138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 800, 800,
5148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
5156fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SkCanvas::kClipToLayer_SaveFlag);
5166fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
5176fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
5186fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
5196fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
5206fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
5216fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
5226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
5236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
5246fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
5266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
527f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
5287db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
5295854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
530f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
5315854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(10, renderer.getIndex());
5326fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
5336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
534f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_contentRejection) {
5358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        auto node = TestUtils::createNode(0, 0, 200, 200,
5368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
5376fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
5386fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
5396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag);
5406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
5416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
5426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
5436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
5446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
547f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5487db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
5496fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
5505854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
5516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
552f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
553b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
5546fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
555f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_simple) {
556b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
557b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
558b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
559b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
560b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
5617435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
562b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
563b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
564b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
565b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
566b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
567b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
568b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
569b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
570b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
571b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
572b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
573b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
574b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
575b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
576b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
577b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
578b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
5797435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
580b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
581b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
582b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
583b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
584b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
585b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
5867db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SkCanvas::SaveFlags)(0));
587b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
588b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
589b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
590f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5917db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
592b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
593f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
594b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
595b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
596b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
597f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
598b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
599b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
600b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
601b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
602b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
603b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
604b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
605b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
606b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
607b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
608b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
609b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
610b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
611b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
612b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
613b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
614b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
615b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
616b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
617b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
618b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
619b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
620b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
621b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
622b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
623b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
624b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
625b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
626b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
627b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
628b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
629b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
630b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
631b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
632b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
633b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
634b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
635b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        int restoreTo = canvas.save(SkCanvas::kMatrixClip_SaveFlag);
636b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
637b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SkCanvas::kMatrixClip_SaveFlag);
638b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SkCanvas::kMatrixClip_SaveFlag);
639b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SkCanvas::kMatrixClip_SaveFlag);
640b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SkCanvas::kMatrixClip_SaveFlag);
641b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
642b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
643b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
644f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6457db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
646b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
647f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
648b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
649b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
650b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
651b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
652b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
653b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
654b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
655b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
656f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_complex) {
657b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
658b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
659b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
660b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
661b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
662b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
663b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
664b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
665b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
666b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
667b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
668b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
669b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
670b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
671b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
672b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
673b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
674b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
675b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
676b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
677b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
678b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
679b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
680b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
681b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
682b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
683b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
684b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
685b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
686b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
687b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
688b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
689b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
690b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
691b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
692b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
693b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
694b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
695b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
696b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
697b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
698b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SkCanvas::SaveFlags)0); // unclipped
699b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag); // clipped
700b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SkCanvas::SaveFlags)0); // unclipped
701b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
702b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
703b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
704b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
705b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
706f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
7077db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
708b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
709f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
710b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(12, renderer.getIndex());
711b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
712b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
713f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
714d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
715d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
71698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
717d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
71898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
71998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
72098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
721d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
722d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
723d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
7240b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
725d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
726d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
727d3daa3198e2212c985c634821682d5819346b653Chris Craik
728e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
729d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
730d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
731d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
732d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
733d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
73498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
735d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
736d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
737d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
738d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
739d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
740e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
741d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
742d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
743d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
7440b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
7458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
74616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
74716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
7480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
7490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
7500b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
75116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
75298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
7530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
75498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
75598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
75698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
7570b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
7587db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
7590b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
7600b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
76198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
7620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
7630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
764f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
76598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            syncedNodeList, sLightCenter);
7660b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
767f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
7680b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
7690b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
7700b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
77198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
7720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
7730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
774f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
775d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
776d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
777d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
778d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
779d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
780d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
781d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
782d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
783d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
784d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
785d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
786d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
78798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
788d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
789d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
790d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
79198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
79298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
793d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
794d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
79598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
79698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
797d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
798d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
799d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
800d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
801d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
802d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
803d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
804d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
805d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
806d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
807d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
808d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
809d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
810d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
811d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
812d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
81398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
814d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
815d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
816d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
81798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
818d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
819d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
82098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
82198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
822d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
823d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
824d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
82598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
82698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
827d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
828d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
829e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
830d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
831d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
832d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
833d3daa3198e2212c985c634821682d5819346b653Chris Craik
83416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto child = TestUtils::createNode(50, 50, 150, 150,
83516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
83616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
8370b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
8380b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
8390b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
84016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
84198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
84298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
8430b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8440b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
84516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 200, 200,
84616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
84716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
8480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
8490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
8500b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
8510b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8520b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
8530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
8540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
85516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
85698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
85798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
8580b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8597db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
8600b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
86198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
8620b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
8630b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
8640b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
865f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
86698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            syncedList, sLightCenter);
8670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
868f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
8690b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(13, renderer.getIndex());
8700b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8710b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
8720b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
8730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
8740b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
8750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
876161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
877161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
878161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
879161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
880161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
881161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
88216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
8838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
884161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
885161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
886161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
887161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
888161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
889161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
890f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, zReorder) {
891d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ZReorderTestRenderer : public TestRendererBase {
892d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
893d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
894d3daa3198e2212c985c634821682d5819346b653Chris Craik            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
895d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
896d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
897d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
898d3daa3198e2212c985c634821682d5819346b653Chris Craik
89916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 100, 100,
9008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
901161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
902161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
903161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
904161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
905161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
906161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
907161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
908161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
909161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
910161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
911161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
912161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
913161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
914f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
9157db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(parent), sLightCenter);
916161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
917f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
918161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    EXPECT_EQ(10, renderer.getIndex());
919161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
920161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
921f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, projectionReorder) {
9228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
9238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
9248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
9258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
9268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
9278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
9288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
9298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
9308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
9318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
9328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
9338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
9348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
9358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
9368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
9378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
9388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
9398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(50, 50, 0); // TODO: should scroll be respected here?
9408d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
9418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
9428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
9438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
9448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
9458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
9468d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
9478d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
9488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
9498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
9508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
9518d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
9528d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
9538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
9548d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
9558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
9568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
9578d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
9588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
9598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
9608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
9618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
9628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
9638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
9648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
9658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
9668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
9678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
9688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
9698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
9708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
9718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
9728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
9738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
9748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
9758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
9768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
9778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
9788d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
9798d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
9808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
9818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(0, 50, 100, 100,
9828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
9838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
9848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
9858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
9868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
9878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
9888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
9898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
9908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
9918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
9928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
9938d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
9948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
9958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
9968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
997f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
9987db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(parent), sLightCenter);
9998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1000f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
10018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
10028d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
10038d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
100498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
100598787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
100616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return TestUtils::createNode(0, 0, 100, 100,
10078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
100816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
100916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
101098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
101198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
101298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
101398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
101498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
101598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1016f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, shadow) {
1017d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1018d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1019d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1020d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
102198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
102298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(op.casterPath->isRect(nullptr));
102398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowMatrixXY);
102498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
102598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
102698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
102798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowMatrixZ);
1028d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1029d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1030d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1031d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1032d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1033161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
10348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
10358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
103698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
103798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1038d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
103998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1040f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
10417db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(parent), sLightCenter);
104298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1043f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
104498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
104598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
104698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1047f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, shadowSaveLayer) {
104898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
104998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
105098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
105198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
105298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
105398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
105498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
105598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
105698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
105798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
105898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
105998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
106098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
106198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
106298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
106398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
106498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
106598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
106698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
106798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
106898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
106998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
10708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
10718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
107298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
107398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
107498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
1075d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
107698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
107798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
107898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1079d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1080d3daa3198e2212c985c634821682d5819346b653Chris Craik
1081f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
10827db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
108398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1084f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
108598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
108698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1087d3daa3198e2212c985c634821682d5819346b653Chris Craik
1088f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
108998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
109098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
109198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
109298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
109398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
109498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
109598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
109698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(50, op.lightCenter.x);
109798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(40, op.lightCenter.y);
109898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
109998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
110098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
110198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
110298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
110398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
110498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
110598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
110698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
110798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
110898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1109d3daa3198e2212c985c634821682d5819346b653Chris Craik
11108d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(50, 60, 150, 160,
111116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
111216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
111398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
111498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
111598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
111698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
111798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
111816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
111998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
112098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
112198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
112298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
112398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
112498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
112598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
112698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
112798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
11287db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
112998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
113098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
1131f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
113298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            syncedList, (Vector3) { 100, 100, 100 });
113398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1134f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
113598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
113698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
113798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
113898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1139d3daa3198e2212c985c634821682d5819346b653Chris Craik}
114076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1141f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, shadowLayering) {
114298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
114398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
114498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
114598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
114698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
114798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
114898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
114998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
115098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
115198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
115298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
11538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
11548d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
115598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
115698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
115798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
115898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
115998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1160f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
11617db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(parent), sLightCenter);
116298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1163f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
116498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
116598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
116698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
116716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
116876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
1169d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
1170d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1171d3daa3198e2212c985c634821682d5819346b653Chris Craik        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1172d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
1173d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1174d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
1175d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
1176d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1177d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1178d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1179d3daa3198e2212c985c634821682d5819346b653Chris Craik
118016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
118116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
118216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
118376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
118476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
118576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
118616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
118776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1188f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
11897db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck            TestUtils::createSyncedNodeList(node), sLightCenter);
119076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
1191f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
119276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
119376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
119476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1195f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
119676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
119776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
119876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
119976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
120076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
120176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
120276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
120376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1204f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropClipping) {
120576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
120676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
120776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
120876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
120976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
121076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
121176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
121276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
121376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1214f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropRevealClip) {
121576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
121676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
121776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
121876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
121976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
122076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
122176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
122276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
122376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
122476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1225f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropOutlineClip) {
122676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
122776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
122876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
122976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
123076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
123176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
123276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
123376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
123476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
123576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
123676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1237f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropTransform) {
123876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
123976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
124076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
124176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
124276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
124376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
124476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
124576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
124676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
124776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
124876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
124976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
125076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
125176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
125276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
125376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
125476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
125576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
125676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
125776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
125876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
125976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
126076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
126176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
126276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
126376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
126476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
126576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
126676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
126776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
126876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
1269161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
12708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
12718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
12728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
12738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
12748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
12758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
12768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
12778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
12788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
12798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
12808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
12818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
12828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
12838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
12848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
12858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
12868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
128716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
12888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
12898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
12908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
12918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
12928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
12938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
12948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
12958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
12968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
12978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
12988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
12998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
13008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
13018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
13028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
13038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
13048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
13058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
13068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
13078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
13088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
13098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
13108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
13118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
13128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
13138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
13148ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
13158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
13168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
131716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 10000, 10000,
131816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
13198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
13208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
13218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
132216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
132316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
132416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
132516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
132616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
13278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
13287db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
13298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1330f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
13318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
1332f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
13338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
13348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
13358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
13368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
13378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1338f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
13398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
13408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
13418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
13428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
13438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
13448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
13458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
13465430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
13478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
13488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
13498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
13508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
13518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
13528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
13538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1354f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
13558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
13568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
13578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
13588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
13598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
13608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
13618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
13628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
13638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
13648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
13658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
13668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
13678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
13688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
13695430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
13708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
13718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
13728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1373f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
13748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
13758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
13768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
13778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
13788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
13798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
13808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
13818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
13828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
13835430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
13848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
13858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
13868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
13876fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
13886fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
1389