FrameBuilderTests.cpp revision dccca44ffda4836b56a21da95a046c9708ffd49c
1b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik/*
25ea1724be4d3b6039818f91fc087e1216c1463d5Chris Craik * Copyright (C) 2016 The Android Open Source Project
3b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
4b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Licensed under the Apache License, Version 2.0 (the "License");
5b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * you may not use this file except in compliance with the License.
6b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * You may obtain a copy of the License at
7b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
8b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *      http://www.apache.org/licenses/LICENSE-2.0
9b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik *
10b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * Unless required by applicable law or agreed to in writing, software
11b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * distributed under the License is distributed on an "AS IS" BASIS,
12b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * See the License for the specific language governing permissions and
14b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik * limitations under the License.
15b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik */
16b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
17b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <gtest/gtest.h>
18b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
19b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <BakedOpState.h>
20d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik#include <DeferredLayerUpdater.h>
21f158b49c888f722194afe5a80539a2b020c130bcChris Craik#include <FrameBuilder.h>
228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik#include <LayerUpdateQueue.h>
23b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordedOp.h>
24b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <RecordingCanvas.h>
258160f20b0aca8c6595d4b385d673f59b6bcd16a4Chris Craik#include <tests/common/TestUtils.h>
26b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
27b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik#include <unordered_map>
28b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
29b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace android {
30b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craiknamespace uirenderer {
31b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikconst LayerUpdateQueue sEmptyLayerUpdateQueue;
336e068c0182f6f85bccb855a647510724d1c65a13Chris Craikconst FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
346e068c0182f6f85bccb855a647510724d1c65a13Chris Craik
3598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik/**
375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual class implemented by each test to redirect static operation / state transitions to
385854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * virtual methods.
396fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
415854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * and allows Renderer vs Dispatching behavior to be merged.
426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * onXXXOp methods fail by default - tests should override ops they expect
44d3daa3198e2212c985c634821682d5819346b653Chris Craik * startRepaintLayer fails by default - tests should override if expected
456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * startFrame/endFrame do nothing by default - tests should override to intercept
466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik */
475854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestRendererBase {
486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikpublic:
495854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    virtual ~TestRendererBase() {}
50d3daa3198e2212c985c634821682d5819346b653Chris Craik    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
51a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer creation not expected in this test";
52a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        return nullptr;
53a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
55a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer repaint not expected in this test";
56a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
57a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void endLayer() {
58a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer updates not expected in this test";
59a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
6098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
61e4db79de127cfe961195f52907af8451026eaa20Chris Craik    virtual void endFrame(const Rect& repaintRect) {}
625854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
6315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for single draw methods
6415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
65a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void on##Type(const Type&, const BakedOpState&) { \
66a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << #Type " not expected in this test"; \
67a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
687cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X)
6915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
7115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for merged draw methods
7215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
7515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
767cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X)
7715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
795854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int getIndex() { return mIndex; }
805854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
815854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikprotected:
825854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int mIndex = 0;
835854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik};
846fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
855854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik/**
865854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Dispatches all static methods to similar formed methods on renderer, which fail by default but
878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * are overridden by subclasses per test.
885854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik */
895854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestDispatcher {
905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikpublic:
9115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define single op methods, which redirect to TestRendererBase
9215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
935854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
945854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik        renderer.on##Type(op, state); \
956fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
967cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X);
9715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
9815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
9915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define merged op methods, which redirect to TestRendererBase
10015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
10115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
10215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        renderer.onMerged##Type##s(opList); \
10315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
1047cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X);
10515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
1066fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik};
107b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1085854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass FailRenderer : public TestRendererBase {};
1096fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
110f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simple) {
111d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleTestRenderer : public TestRendererBase {
112d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
11398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
114d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
115d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(100u, width);
116d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(200u, height);
117d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
118d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
119d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
120d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
121d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
122d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
123d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
124e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
125d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
126d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
127d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
128d3daa3198e2212c985c634821682d5819346b653Chris Craik
1298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
1308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
131ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
132b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
133b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawBitmap(bitmap, 10, 10, nullptr);
134b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
135f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1366e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
1375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleTestRenderer renderer;
138f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
1406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
1416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
142f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simpleStroke) {
143386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    class SimpleStrokeTestRenderer : public TestRendererBase {
144386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    public:
145386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
146386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(0, mIndex++);
147386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            // even though initial bounds are empty...
148386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_TRUE(op.unmappedBounds.isEmpty())
149386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "initial bounds should be empty, since they're unstroked";
150386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
151386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "final bounds should account for stroke";
152386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        }
153386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    };
154386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
155386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
156386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
157386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        SkPaint strokedPaint;
158386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        strokedPaint.setStrokeWidth(10);
159386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        canvas.drawPoint(50, 50, strokedPaint);
160386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    });
161f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1626e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
163386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    SimpleStrokeTestRenderer renderer;
164f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
165386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    EXPECT_EQ(1, renderer.getIndex());
166386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik}
167386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
168f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simpleRejection) {
1698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
171eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
1726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
1736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
1756fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
176f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
1776e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
178b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1795854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
180f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
181b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
182b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
183f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, simpleBatching) {
184a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
185d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleBatchingTestRenderer : public TestRendererBase {
186d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
187d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
188a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
189d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
190d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
191a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
192d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
193d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
194d3daa3198e2212c985c634821682d5819346b653Chris Craik
1958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
19715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
19815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
199b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
200b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
201b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
202eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
203a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
204b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
206b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawBitmap(bitmap, 5, 0, nullptr);
207b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
208b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
209b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
210b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
211f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
2126e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
2135854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
214f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
215a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
21615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
217a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
218a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
219f6c20e4b4232e30901676bcdf1aed64801d50c7eChris CraikTEST(FrameBuilder, clippedMerging) {
22093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
22193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
22293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
22393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
22493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
22593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
22693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
22793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
22893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
22993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
23093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
23193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    auto node = TestUtils::createNode(0, 0, 100, 100,
23293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
23393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
23493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
23693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
23793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 0, 40, nullptr);
23893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
23993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
24093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
24193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 0, nullptr);
24293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
24493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
24593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 80, 40, nullptr);
24693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
24793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
24893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
24993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 70, nullptr);
25093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
25193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
252f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
2536e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
25493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
255f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
25693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
25793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
25893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
259f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, textMerging) {
260d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
261d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
262d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
263d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
264d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
265d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
266d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
267d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
268d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
269d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
270d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
271d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
272d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            [](RenderProperties& props, TestCanvas& canvas) {
273d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
274d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
275d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
276d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
277dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
278dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
279d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
280f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
2816e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
282d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
283f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
284d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
285d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
286d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
287f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, textStrikethrough) {
288a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
289a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
290a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
291a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
292a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
293a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
29415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
29515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
29615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
29715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
298a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
299a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
3008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 2000,
3018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
302a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
303a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
304a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
305a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setStrikeThruText(true);
30642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
307a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
308dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
309a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
310a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
311f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
3126e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
313a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
314f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
315a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
316d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
317b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
318b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
3197c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craikstatic auto styles = {
3207c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
3217c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3227c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris CraikTEST(FrameBuilder, textStyle) {
3237c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    class TextStyleTestRenderer : public TestRendererBase {
3247c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    public:
3257c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
3267c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(0, mIndex);
3277c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(3u, opList.count);
3287c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            mIndex += opList.count;
3297c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3307c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            int index = 0;
3317c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            for (auto style : styles) {
3327c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                auto state = opList.states[index++];
3337c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(style, state->op->paint->getStyle())
3347c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Remainder of validation relies upon stable merged order";
3357c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(0, state->computedState.clipSideFlags)
3367c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Clipped bounds validation requires unclipped ops";
3377c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            }
3387c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3397c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect fill = opList.states[0]->computedState.clippedBounds;
3407c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect stroke = opList.states[1]->computedState.clippedBounds;
3417c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
3427c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                    << "Stroke+Fill should be same as stroke";
3437c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3447c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_TRUE(stroke.contains(fill));
3457c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_FALSE(fill.contains(stroke));
3467c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3477c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect outsetFill(fill);
3487c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            outsetFill.outset(10);
3497c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, outsetFill);
3507c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
3517c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    };
3527c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
3537c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
3547c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint paint;
3557c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
3567c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setAntiAlias(true);
3577c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextSize(50);
3587c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setStrokeWidth(10);
3597c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
3607c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // draw 3 copies of the same text overlapping, each with a different style.
3617c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // They'll get merged, but with
3627c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        for (auto style : styles) {
3637c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            paint.setStyle(style);
364dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
3657c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
3667c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    });
3677c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
3687c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
3697c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    TextStyleTestRenderer renderer;
3707c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
3717c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
3727c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik}
3737c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
374f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer) {
375d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    class TextureLayerTestRenderer : public TestRendererBase {
376d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
377d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
378d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
379e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
380d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
381d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
382d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
383d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
384d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
385d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
386d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
387d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
388d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
389d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [](Matrix4* transform) {
390d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        transform->loadTranslate(5, 5, 0);
391d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
392d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
393d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
394d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
395eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
396d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
397d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
398d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
399d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
400f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4016e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
402d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    TextureLayerTestRenderer renderer;
403f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
404d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
405d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
406d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
407223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris CraikTEST(FrameBuilder, functor_reject) {
408223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
409223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
410223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
411223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
412223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
413223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
414223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
415223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
416223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
417223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
418223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
419223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
420223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.callDrawGLFunction(&noopFunctor);
421223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
422223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
423223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
424223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            TestUtils::createSyncedNodeList(scrolledFunctorView), sLightGeometry, nullptr);
425223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
426223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
427223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
428223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
429223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
430f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderNode) {
431d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
432d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
433d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
434d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
435d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
4365430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
437d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
438d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
439d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
440d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
441d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
442d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
443d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
444d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
445d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
446d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
447d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
448d3daa3198e2212c985c634821682d5819346b653Chris Craik
4498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(10, 10, 110, 110,
4508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
451b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
452b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
453b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
454b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
455b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
457d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
458ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
459ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
460ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
461ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
462eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
463ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
464d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
465ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
466b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
467b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
468f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4696e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
4705854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
471f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
472223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
473b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
474b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
475f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, clipped) {
476d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
477d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
478d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
479d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
480d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
481e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
482d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
483d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
484d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
485d3daa3198e2212c985c634821682d5819346b653Chris Craik
4868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
4878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
488ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
489ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawBitmap(bitmap, 0, 0, nullptr);
490ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
491ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
492f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
4930b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
4946e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
4955854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
496f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
497ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
498ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
499f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_simple) {
500d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
501d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
502d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
503d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
504d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
505d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
506d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
507d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
508d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
509d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
510d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
511d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
512d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
513d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
5145430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
515e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
516d3daa3198e2212c985c634821682d5819346b653Chris Craik
517d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
518d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
519d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
520d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
521d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
522d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
523d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
524e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
525d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
526d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
527d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
528d3daa3198e2212c985c634821682d5819346b653Chris Craik
5298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
5308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
531eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
5326fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
5336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
535f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5366e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
5375854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
538f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
5395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex());
540b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
5416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
542f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_nested) {
543d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
544d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
545d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
546d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
547d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
548d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
549d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
550d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
551d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
552d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
553d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
554d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
555d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
556d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
557d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
558d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
559d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
560d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
561d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
562d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
563d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
564d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
565d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
566d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
56798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
568d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
569d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
570e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
571d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
572d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
573d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
574d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
575d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
5765430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
577d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
5785430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
579d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
580d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
581d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
582d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
583d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
584d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
5855430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
586d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
587d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
5885430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
589d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
590d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
591d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
592d3daa3198e2212c985c634821682d5819346b653Chris Craik
5938d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 800, 800,
5948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
595eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
5966fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
5976fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
598eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
5996fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
6006fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
6016fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
6026fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
6036fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
6046fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6056fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
6066fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
607f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
6086e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
6095854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
610f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
6115854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(10, renderer.getIndex());
6126fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
6136fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
614f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_contentRejection) {
6158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        auto node = TestUtils::createNode(0, 0, 200, 200,
6168d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
617eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
6186fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
619eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
6206fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6216fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
6226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
6236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6246fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
6266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
627f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6286e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
6296fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
6305854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
6316fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
632f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
633b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
6346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
635f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_simple) {
636b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
637b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
638b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
639b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
640b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
6417435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
642b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
643b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
644b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
645b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
646b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
647b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
648b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
649b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
650b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
651b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
652b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
653b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
654b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
655b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
656b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
657b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
658b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
6597435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
660b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
661b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
662b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
663b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
664b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
665b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
666eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
667b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
668b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
669b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
670f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6716e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
672b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
673f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
674b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
675b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
676b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
677f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
678b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
679b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
680b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
681b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
682b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
683b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
684b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
685b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
686b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
687b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
688b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
689b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
690b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
691b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
692b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
693b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
694b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
695b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
696b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
697b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
698b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
699b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
700b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
701b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
702b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
703b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
704b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
705b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
706b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
707b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
708b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
709b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
710b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
711b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
712b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
713b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
714b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
715eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
716b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
717eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
718eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
719eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
720eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
721b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
722b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
723b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
724f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
7256e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
726b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
727f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
728b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
729b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
730b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
731b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
7324876de16e34622634266d09522c9153c78c7c2fbChris CraikTEST(FrameBuilder, saveLayerUnclipped_clearClip) {
7334876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
7344876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
7354876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
7364876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
7374876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7384876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
7394876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
7404876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
7414876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
7424876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
7434876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
7444876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
7454876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
7464876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
7474876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7484876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
7494876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
7504876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7514876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
7524876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
7534876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
7544876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
7554876de16e34622634266d09522c9153c78c7c2fbChris Craik
7564876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7574876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
7584876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
7594876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
7604876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
7614876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
7624876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
7634876de16e34622634266d09522c9153c78c7c2fbChris Craik
7644876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
7654876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
7664876de16e34622634266d09522c9153c78c7c2fbChris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
7674876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
7684876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
7694876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
7704876de16e34622634266d09522c9153c78c7c2fbChris Craik}
7714876de16e34622634266d09522c9153c78c7c2fbChris Craik
7724876de16e34622634266d09522c9153c78c7c2fbChris CraikTEST(FrameBuilder, saveLayerUnclipped_reject) {
7734876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7744876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
7754876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
7764876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
7774876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
7784876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
7794876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
7804876de16e34622634266d09522c9153c78c7c2fbChris Craik
7814876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
7824876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
7834876de16e34622634266d09522c9153c78c7c2fbChris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
7844876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
7854876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
7864876de16e34622634266d09522c9153c78c7c2fbChris Craik}
7874876de16e34622634266d09522c9153c78c7c2fbChris Craik
788b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
789b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
790b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
791b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
792f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_complex) {
793b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
794b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
795b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
796b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
797b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
798b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
799b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
800b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
801b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
802b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
803b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
804b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
805b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
806b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
807b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
808b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
809b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
810b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
811b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
812b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
813b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
814b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
815b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
816b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
817b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
818b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
819b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
820b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
821b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
822b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
823b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
824b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
825b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
826b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
827b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
828b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
829b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
830b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
831b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
832b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
833b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
834eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
835eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
836eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
837b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
838b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
839b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
840b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
841b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
842f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
8436e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
844b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
845f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
846b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(12, renderer.getIndex());
847b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
848b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
849f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
850d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
851d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
85298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
853d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
85498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
85598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
85698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
857d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
858d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
859d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
8600b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
861d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
862d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
863d3daa3198e2212c985c634821682d5819346b653Chris Craik
864e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
865d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
866d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
867d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
868d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
869d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
87098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
871d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
872d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
873d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
874d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
875d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
876e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
877d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
878d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
879d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
8800b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
88216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
88316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
8840b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
8850b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
8860b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
88716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
88898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
8890b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
89098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
89198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
89298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
8930b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8947db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
8950b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8960b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
89798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
8980b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
8990b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
900f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
9016e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedNodeList, sLightGeometry, nullptr);
9020b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
903f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
9040b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
9050b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9060b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
90798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
9080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
9090b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
910f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
911d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
912d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
913d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
914d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
915d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
916d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
917d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
918d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
919d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
920d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
921d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
922d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
92398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
924d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
925d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
926d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
92798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
92898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
929d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
930d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
93198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
93298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
933d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
934d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
935d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
936d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
937d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
938d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
939d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
940d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
941d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
942d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
943d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
944d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
945d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
946d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
947d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
948d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
94998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
950d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
951d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
952d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
95398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
954d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
955d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
95698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
95798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
958d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
959d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
960d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
96198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
96298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
963d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
964d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
965e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
966d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
967d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
968d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
969d3daa3198e2212c985c634821682d5819346b653Chris Craik
97016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto child = TestUtils::createNode(50, 50, 150, 150,
97116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
97216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
9730b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
9740b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
9750b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
97616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
97798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
97898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
9790b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9800b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
98116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 200, 200,
98216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
98316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
9840b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
9850b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
9860b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
9870b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
988eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
9890b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
9900b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
99116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
99298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
99398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
9940b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9957db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
9960b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
99798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
9980b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
9990b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
10000b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1001f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
10026e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedList, sLightGeometry, nullptr);
10030b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
1004f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
10050b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(13, renderer.getIndex());
10060b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
10070b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
10080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
10090b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
10100b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
10110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1012161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
1013161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
1014161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
1015161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
1016161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1017161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
101816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
10198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
1020161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
1021161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1022161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
1023161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
1024161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1025161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1026f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, zReorder) {
1027d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ZReorderTestRenderer : public TestRendererBase {
1028d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1029d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1030d3daa3198e2212c985c634821682d5819346b653Chris Craik            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
1031d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
1032d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1033d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1034d3daa3198e2212c985c634821682d5819346b653Chris Craik
103516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 100, 100,
10368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1037161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1038161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
1039161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
1040161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
1041161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
1042161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
1043161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
1044161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
1045161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
1046161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
1047161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
1048161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
1049161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1050f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
10516e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
1052161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
1053f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1054161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    EXPECT_EQ(10, renderer.getIndex());
1055161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1056161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
1057f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, projectionReorder) {
10588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
10598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
10608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
10618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
10628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
10638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
10648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
10658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
10668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
10678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
10688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
10698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
10708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1071678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
10728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
10748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
10758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1076678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1077678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1078678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1079678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
10808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
10828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
10838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
10848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1085678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
10868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
10888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
10898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1090678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
10918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
10928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
10938d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
10948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
10958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
10968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
10978d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
10988d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
10998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
11008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
11018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
11028d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
11038d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
11048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
11058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
11068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
11078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
11088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
11098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
11108d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
11128d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
11138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
11158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
11168d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
11178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
11188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
11208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
11218d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(0, 50, 100, 100,
11238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
11248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
11258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
11268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
11278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
11288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
11308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1131678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1132678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1133678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1134eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
11358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
11368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
11378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
11388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
11398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
11408d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1141f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
11426e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
11438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1144f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
11458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
11468d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
11478d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1148678ff81105753656aa4822f4f675ef96dc9d2b83Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
1149678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1150678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1151678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1152678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1153678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1154678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1155678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1156678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1157678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1158678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1159678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1160678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1161678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1162678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1163678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1164678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1165678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1166678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1167678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1168678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1169678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1170678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1171678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1172678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1173678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1174678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1175678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1176678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1177678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1178678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1179678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1180678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
1181678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1182678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1183678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1184678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1185678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1186678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1187678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1188678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1189678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1190678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1191678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1192678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1193678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1194678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1195678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1196678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1197678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto child = TestUtils::createNode(100, 100, 300, 300,
1198678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1199678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1200678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1201678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1202678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1203678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1204678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1205678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1206678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1207678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1208678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1209678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1210678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1211678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1212678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1213678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1214678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1215678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1216678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1217678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1218678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1219678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1220678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1221678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto syncedList = TestUtils::createSyncedNodeList(parent);
1222678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1223678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
1224678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
1225678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            syncedList, sLightGeometry, nullptr);
1226678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1227678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1228678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1229678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1230678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1231678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1232678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1233678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1234a748c08241e43fc68c7c34767d819aef5183936eChris CraikRENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
1235a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1236a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1237a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1238a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1239a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1240a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1241a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1242a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1243a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1244a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1245a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1246a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1247a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1248a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1249a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1250a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
1251a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1252a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1253a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1254a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1255a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1256a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1257a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1258a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1259a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1260a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1261a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1262a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1263a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1264a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1265a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1266a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto child = TestUtils::createNode(0, 0, 400, 400,
1267a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1268a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
1269a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
1270a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1271a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1272a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1273a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1274a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1275a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1276a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1277a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1278a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1279a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1280a748c08241e43fc68c7c34767d819aef5183936eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
1281a748c08241e43fc68c7c34767d819aef5183936eChris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
1282a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1283a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1284a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1285a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1286a748c08241e43fc68c7c34767d819aef5183936eChris Craik
128798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
128898787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
128916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return TestUtils::createNode(0, 0, 100, 100,
12908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
129116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
129216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
129398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
129498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
129598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
129698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
129798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
129898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
12996e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadow) {
1300d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1301d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1302d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1303d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
130498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
13056e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
13066e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
130798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
130898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
130998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
13106e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1311d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1312d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1313d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1314d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1315d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1316161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
13178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
13188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
131998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
132098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1321d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
132298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1323f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13246e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, &Caches::getInstance());
132598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1326f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
132798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
132898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
132998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13306e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
133198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
133298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
133398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
133498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
133598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
133698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
133798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
133898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
13396e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
13406e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
134198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
134298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
134398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
134498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
134598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
134698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
134798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
134898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
134998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
135098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
135198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
135298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
13548d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
135598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
135698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1357eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1358d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
135998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
136098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
136198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1362d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1363d3daa3198e2212c985c634821682d5819346b653Chris Craik
1364f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13656e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
13666e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
13676e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            &Caches::getInstance());
136898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1369f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
137098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
137198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1372d3daa3198e2212c985c634821682d5819346b653Chris Craik
1373f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
137498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
137598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
137698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
137798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
137898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
137998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
138098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
13816e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
13826e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
13836e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
138498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
138598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
138698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
138798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
138898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
138998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
139098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
139198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
139298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
139398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
139498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1395d3daa3198e2212c985c634821682d5819346b653Chris Craik
13968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(50, 60, 150, 160,
139716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
139816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
139998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1400eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
140198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
140298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
140398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
140416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
140598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
140698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
140798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
140898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
140998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
141098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
141198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
141298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
141398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
14147db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
141598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
141698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
1417f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
14186e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedList,
14196e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30},
14206e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            &Caches::getInstance());
142198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1422f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
142398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
142498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
142598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
142698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1427d3daa3198e2212c985c634821682d5819346b653Chris Craik}
142876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1429f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, shadowLayering) {
143098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
143198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
143298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
143398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
143498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
143598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
143698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
143798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
143898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
143998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
144098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
14418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
14428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
144398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
144498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
144598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
144698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
144798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1448f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
14496e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
14506e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
14516e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            &Caches::getInstance());
145298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1453f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
145498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
145598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
145698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
145716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
145876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
1459d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
1460d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1461d3daa3198e2212c985c634821682d5819346b653Chris Craik        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1462d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
1463d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1464d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
1465d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
1466d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1467d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1468d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1469d3daa3198e2212c985c634821682d5819346b653Chris Craik
147016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
147116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
147216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
147376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
147476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
147576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
147616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
147776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1478f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
14796e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
148076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
1481f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
148276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
148376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
148476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1485f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
148676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
148776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
148876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
148976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
149076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
149176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
149276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
149376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1494f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropClipping) {
149576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
149676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
149776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
149876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
149976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
150076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
150176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
150276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
150376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1504f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropRevealClip) {
150576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
150676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
150776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
150876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
150976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
151076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
151176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
151276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
151376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
151476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1515f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropOutlineClip) {
151676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
151776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
151876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
151976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
152076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
152176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
152276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
152376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
152476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
152576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
152676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1527f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropTransform) {
152876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
152976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
153076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
153176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
153276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
153376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
153476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
153576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
153676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
153776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
153876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
153976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
154076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
154176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
154276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
154376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
154476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
154576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
154676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
154776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
154876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
154976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
155076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
155176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
155276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
155376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
155476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
155576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
155676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
155776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
155876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
1559161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
15608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
15618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
15628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
15638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
15648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
15658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
15668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
15678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
15688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
15698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
15708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
15718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
15728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
15738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
15748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
15758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
15768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
157716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
15788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
15798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
15808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
15818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
15828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
15848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
15858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
15868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
15878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
15888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
15908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
15918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
15938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
15948ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
15968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
15978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
15998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
16008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
16018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
16028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
16038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
16048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
16068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
160716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 10000, 10000,
160816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
16098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
16108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
16118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
161216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
161316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
161416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
161516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
161616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
16178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16187db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
16198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16206e068c0182f6f85bccb855a647510724d1c65a13Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
16216e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            nodes, sLightGeometry, nullptr);
16228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
1623f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
16248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
16268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
16278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1629f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
16308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
16338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
16348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
16368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
16375430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
16388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
16398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
16408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
16418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
16428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
16438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1645f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
16468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
16498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
16508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
16518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
16528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
16538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
16548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
16558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
16568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
16588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
16598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
16605430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
16618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
16628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1664f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
16658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
16688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
16698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
16708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
16718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
16738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
16745430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
16758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
16768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
16796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
1680