FrameBuilderTests.cpp revision 223e3b6c2b53a66b4efd8040edfe23ed1a5c925e
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);
277d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
278d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        TestUtils::drawTextToCanvas(&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++) {
308a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            TestUtils::drawTextToCanvas(&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
319f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer) {
320d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    class TextureLayerTestRenderer : public TestRendererBase {
321d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
322d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
323d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
324e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
325d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
326d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
327d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
328d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
329d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
330d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
331d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
332d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
333d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
334d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [](Matrix4* transform) {
335d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        transform->loadTranslate(5, 5, 0);
336d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
337d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
338d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
339d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
340eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
341d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
342d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
343d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
344d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
345f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
3466e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
347d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    TextureLayerTestRenderer renderer;
348f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
349d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
350d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
351d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
352223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris CraikTEST(FrameBuilder, functor_reject) {
353223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
354223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
355223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
356223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
357223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
358223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
359223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
360223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
361223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
362223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
363223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
364223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
365223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.callDrawGLFunction(&noopFunctor);
366223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
367223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
368223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
369223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            TestUtils::createSyncedNodeList(scrolledFunctorView), sLightGeometry, nullptr);
370223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
371223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
372223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
373223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
374223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
375f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderNode) {
376d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
377d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
378d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
379d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
380d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
3815430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
382d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
383d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
384d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
385d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
386d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
387d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
388d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
389d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
390d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
391d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
392d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
393d3daa3198e2212c985c634821682d5819346b653Chris Craik
3948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(10, 10, 110, 110,
3958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
396b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
397b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
398b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
399b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
400b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4018d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
402d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
403ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
404ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
405ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
406ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
407eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
408ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
409d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
410ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
411b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
412b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
413f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4146e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
4155854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
416f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
417223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
418b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
419b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
420f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, clipped) {
421d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
422d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
423d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
424d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
425d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
426e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
427d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
428d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
429d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
430d3daa3198e2212c985c634821682d5819346b653Chris Craik
4318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
4328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
433ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
434ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawBitmap(bitmap, 0, 0, nullptr);
435ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
436ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
437f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
4380b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
4396e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
4405854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
441f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
442ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
443ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
444f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_simple) {
445d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
446d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
447d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
448d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
449d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
450d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
451d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
452d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
453d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
454d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
455d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
456d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
457d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
458d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
4595430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
460e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
461d3daa3198e2212c985c634821682d5819346b653Chris Craik
462d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
463d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
464d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
465d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
466d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
467d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
468d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
469e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
470d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
471d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
472d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
473d3daa3198e2212c985c634821682d5819346b653Chris Craik
4748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
4758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
476eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
4776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
4786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
4796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
480f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
4816e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
4825854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
483f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
4845854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex());
485b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
4866fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
487f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_nested) {
488d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
489d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
490d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
491d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
492d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
493d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
494d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
495d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
496d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
497d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
498d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
499d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
500d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
501d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
502d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
503d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
504d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
505d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
506d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
507d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
508d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
509d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
510d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
511d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
51298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
513d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
514d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
515e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
516d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
517d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
518d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
519d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
520d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
5215430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
522d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
5235430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
524d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
525d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
526d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
527d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
528d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
529d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
5305430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
531d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
532d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
5335430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
534d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
535d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
536d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
537d3daa3198e2212c985c634821682d5819346b653Chris Craik
5388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 800, 800,
5398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
540eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
5416fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
5426fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
543eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
5446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
5456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
5466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
5476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
5486fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
5496fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5506fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
5516fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
552f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
5536e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
5545854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
555f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
5565854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(10, renderer.getIndex());
5576fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
5586fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
559f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayer_contentRejection) {
5608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        auto node = TestUtils::createNode(0, 0, 200, 200,
5618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
562eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
5636fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
564eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
5656fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
5666fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
5676fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
5686fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
5696fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5706fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
5716fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
572f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5736e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
5746fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
5755854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
5766fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
577f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
578b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
5796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
580f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_simple) {
581b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
582b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
583b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
584b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
585b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
5867435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
587b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
588b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
589b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
590b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
591b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
592b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
593b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
594b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
595b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
596b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
597b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
598b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
599b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
600b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
601b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
602b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
603b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
6047435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
605b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
606b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
607b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
608b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
609b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
610b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
611eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
612b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
613b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
614b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
615f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6166e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
617b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
618f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
619b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
620b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
621b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
622f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
623b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
624b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
625b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
626b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
627b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
628b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
629b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
630b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
631b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
632b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
633b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
634b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
635b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
636b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
637b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
638b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
639b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
640b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
641b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
642b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
643b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
644b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
645b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
646b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
647b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
648b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
649b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
650b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
651b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
652b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
653b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
654b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
655b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
656b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
657b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
658b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
659b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
660eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
661b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
662eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
663eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
664eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
665eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
666b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
667b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
668b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
669f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6706e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
671b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
672f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
673b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
674b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
675b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
676b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
6774876de16e34622634266d09522c9153c78c7c2fbChris CraikTEST(FrameBuilder, saveLayerUnclipped_clearClip) {
6784876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
6794876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
6804876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
6814876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
6824876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
6834876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
6844876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
6854876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
6864876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
6874876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
6884876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
6894876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
6904876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
6914876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
6924876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
6934876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
6944876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
6954876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
6964876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
6974876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
6984876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
6994876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
7004876de16e34622634266d09522c9153c78c7c2fbChris Craik
7014876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7024876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
7034876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
7044876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
7054876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
7064876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
7074876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
7084876de16e34622634266d09522c9153c78c7c2fbChris Craik
7094876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
7104876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
7114876de16e34622634266d09522c9153c78c7c2fbChris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
7124876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
7134876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
7144876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
7154876de16e34622634266d09522c9153c78c7c2fbChris Craik}
7164876de16e34622634266d09522c9153c78c7c2fbChris Craik
7174876de16e34622634266d09522c9153c78c7c2fbChris CraikTEST(FrameBuilder, saveLayerUnclipped_reject) {
7184876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7194876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
7204876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
7214876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
7224876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
7234876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
7244876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
7254876de16e34622634266d09522c9153c78c7c2fbChris Craik
7264876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
7274876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
7284876de16e34622634266d09522c9153c78c7c2fbChris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
7294876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
7304876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
7314876de16e34622634266d09522c9153c78c7c2fbChris Craik}
7324876de16e34622634266d09522c9153c78c7c2fbChris Craik
733b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
734b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
735b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
736b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
737f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, saveLayerUnclipped_complex) {
738b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
739b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
740b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
741b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
742b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
743b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
744b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
745b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
746b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
747b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
748b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
749b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
750b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
751b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
752b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
753b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
754b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
755b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
756b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
757b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
758b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
759b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
760b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
761b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
762b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
763b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
764b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
765b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
766b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
767b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
768b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
769b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
770b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
771b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
772b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
773b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
774b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
775b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
776b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
777b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
778b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
779eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
780eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
781eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
782b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
783b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
784b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
785b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
786b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
787f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
7886e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
789b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
790f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
791b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(12, renderer.getIndex());
792b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
793b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
794f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
795d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
796d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
79798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
798d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
79998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
80098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
80198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
802d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
803d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
804d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
8050b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
806d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
807d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
808d3daa3198e2212c985c634821682d5819346b653Chris Craik
809e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
810d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
811d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
812d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
813d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
814d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
81598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
816d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
817d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
818d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
819d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
820d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
821e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
822d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
823d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
824d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
8250b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
82716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
82816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
8290b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
8300b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
8310b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
83216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
83398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
8340b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
83598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
83698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
83798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
8380b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8397db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
8400b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8410b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
84298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
8430b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
8440b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
845f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
8466e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedNodeList, sLightGeometry, nullptr);
8470b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
848f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
8490b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
8500b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
8510b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
85298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
8530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
8540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
855f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
856d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
857d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
858d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
859d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
860d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
861d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
862d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
863d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
864d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
865d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
866d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
867d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
86898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
869d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
870d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
871d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
87298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
87398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
874d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
875d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
87698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
87798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
878d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
879d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
880d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
881d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
882d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
883d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
884d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
885d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
886d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
887d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
888d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
889d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
890d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
891d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
892d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
893d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
89498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
895d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
896d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
897d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
89898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
899d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
900d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
90198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
90298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
903d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
904d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
905d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
90698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
90798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
908d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
909d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
910e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
911d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
912d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
913d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
914d3daa3198e2212c985c634821682d5819346b653Chris Craik
91516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto child = TestUtils::createNode(50, 50, 150, 150,
91616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
91716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
9180b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
9190b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
9200b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
92116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
92298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
92398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
9240b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9250b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
92616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 200, 200,
92716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
92816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
9290b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
9300b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
9310b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
9320b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
933eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
9340b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
9350b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
93616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
93798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
93898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
9390b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9407db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
9410b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
94298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
9430b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
9440b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
9450b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
946f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
9476e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedList, sLightGeometry, nullptr);
9480b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
949f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
9500b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(13, renderer.getIndex());
9510b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
9520b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
9530b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
9540b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
9550b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
9560b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
957161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
958161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
959161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
960161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
961161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
962161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
96316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
9648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
965161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
966161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
967161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
968161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
969161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
970161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
971f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, zReorder) {
972d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ZReorderTestRenderer : public TestRendererBase {
973d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
974d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
975d3daa3198e2212c985c634821682d5819346b653Chris Craik            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
976d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
977d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
978d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
979d3daa3198e2212c985c634821682d5819346b653Chris Craik
98016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 100, 100,
9818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
982161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
983161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
984161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
985161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
986161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
987161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
988161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
989161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
990161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
991161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
992161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
993161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
994161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
995f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
9966e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
997161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
998f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
999161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    EXPECT_EQ(10, renderer.getIndex());
1000161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1001161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
1002f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, projectionReorder) {
10038d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
10048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
10058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
10068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
10078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
10088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
10098d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
10108d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
10118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
10128d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
10138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
10148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
10158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1016678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
10178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
10198d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
10208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1021678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1022678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1023678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1024678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
10258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
10278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
10288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
10298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1030678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
10318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
10328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
10338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
10348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1035678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
10368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
10378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
10388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
10398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
10408d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
10418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
10428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
10438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
10448d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
10458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
10468d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
10478d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
10488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
10498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
10508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
10518d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
10528d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
10538d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
10548d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
10558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
10568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
10578d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
10588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
10598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
10608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
10618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
10628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
10638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
10648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
10658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
10668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
10678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(0, 50, 100, 100,
10688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
10698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
10708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
10718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
10728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
10738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
10748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
10758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1076678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1077678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1078678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1079eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
10808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
10818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
10828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
10838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
10848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
10858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1086f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
10876e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
10888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1089f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
10908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
10918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
10928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1093678ff81105753656aa4822f4f675ef96dc9d2b83Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
1094678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1095678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1096678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1097678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1098678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1099678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1100678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1101678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1102678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1103678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1104678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1105678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1106678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1107678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1108678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1109678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1110678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1111678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1112678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1113678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1114678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1115678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1116678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1117678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1118678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1119678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1120678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1121678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1122678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1123678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1124678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1125678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
1126678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1127678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1128678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1129678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1130678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1131678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1132678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1133678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1134678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1135678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1136678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1137678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1138678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1139678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1140678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1141678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1142678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto child = TestUtils::createNode(100, 100, 300, 300,
1143678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1144678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1145678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1146678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1147678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1148678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1149678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1150678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1151678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1152678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1153678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1154678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1155678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1156678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1157678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1158678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1159678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1160678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1161678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1162678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1163678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1164678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1165678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1166678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto syncedList = TestUtils::createSyncedNodeList(parent);
1167678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1168678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
1169678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
1170678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            syncedList, sLightGeometry, nullptr);
1171678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1172678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1173678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1174678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1175678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1176678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1177678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1178678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1179a748c08241e43fc68c7c34767d819aef5183936eChris CraikRENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
1180a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1181a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1182a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1183a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1184a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1185a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1186a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1187a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1188a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1189a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1190a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1191a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1192a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1193a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1194a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1195a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
1196a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1197a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1198a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1199a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1200a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1201a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1202a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1203a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1204a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1205a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1206a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1207a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1208a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1209a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1210a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1211a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto child = TestUtils::createNode(0, 0, 400, 400,
1212a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1213a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
1214a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
1215a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1216a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1217a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1218a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1219a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1220a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1221a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1222a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1223a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1224a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1225a748c08241e43fc68c7c34767d819aef5183936eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
1226a748c08241e43fc68c7c34767d819aef5183936eChris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
1227a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1228a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1229a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1230a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1231a748c08241e43fc68c7c34767d819aef5183936eChris Craik
123298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
123398787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
123416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return TestUtils::createNode(0, 0, 100, 100,
12358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
123616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
123716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
123898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
123998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
124098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
124198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
124298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
124398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
12446e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadow) {
1245d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1246d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1247d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1248d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
124998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
12506e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
12516e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
125298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
125398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
125498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
12556e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1256d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1257d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1258d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1259d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1260d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1261161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
12628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
12638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
126498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
126598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1266d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
126798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1268f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
12696e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, &Caches::getInstance());
127098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1271f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
127298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
127398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
127498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
12756e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
127698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
127798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
127898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
127998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
128098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
128198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
128298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
128398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
12846e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
12856e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
128698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
128798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
128898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
128998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
129098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
129198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
129298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
129398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
129498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
129598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
129698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
129798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
12988d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
12998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
130098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
130198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1302eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1303d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
130498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
130598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
130698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1307d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1308d3daa3198e2212c985c634821682d5819346b653Chris Craik
1309f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13106e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
13116e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
13126e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            &Caches::getInstance());
131398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1314f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
131598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
131698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1317d3daa3198e2212c985c634821682d5819346b653Chris Craik
1318f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
131998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
132098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
132198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
132298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
132398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
132498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
132598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
13266e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
13276e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
13286e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
132998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
133098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
133198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
133298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
133398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
133498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
133598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
133698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
133798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
133898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
133998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1340d3daa3198e2212c985c634821682d5819346b653Chris Craik
13418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(50, 60, 150, 160,
134216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
134316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
134498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1345eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
134698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
134798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
134898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
134916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
135098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
135198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
135298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
135398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
135498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
135598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
135698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
135798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
135898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
13597db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
136098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
136198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
1362f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13636e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedList,
13646e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30},
13656e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            &Caches::getInstance());
136698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1367f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
136898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
136998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
137098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
137198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1372d3daa3198e2212c985c634821682d5819346b653Chris Craik}
137376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1374f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, shadowLayering) {
137598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
137698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
137798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
137898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
137998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
138098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
138198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
138298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
138398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
138498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
138598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
13868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
13878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
138898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
138998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
139098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
139198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
139298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1393f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
13946e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
13956e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50},
13966e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            &Caches::getInstance());
139798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1398f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
139998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
140098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
140198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
140216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
140376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
1404d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
1405d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1406d3daa3198e2212c985c634821682d5819346b653Chris Craik        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1407d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
1408d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1409d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
1410d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
1411d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1412d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1413d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1414d3daa3198e2212c985c634821682d5819346b653Chris Craik
141516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
141616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
141716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
141876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
141976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
142076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
142116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
142276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1423f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
14246e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
142576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
1426f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
142776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
142876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
142976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1430f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
143176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
143276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
143376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
143476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
143576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
143676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
143776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
143876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1439f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropClipping) {
144076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
144176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
144276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
144376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
144476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
144576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
144676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
144776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
144876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1449f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropRevealClip) {
145076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
145176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
145276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
145376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
145476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
145576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
145676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
145776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
145876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
145976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1460f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropOutlineClip) {
146176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
146276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
146376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
146476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
146576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
146676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
146776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
146876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
146976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
147076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
147176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1472f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropTransform) {
147376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
147476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
147576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
147676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
147776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
147876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
147976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
148076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
148176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
148276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
148376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
148476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
148576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
148676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
148776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
148876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
148976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
149076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
149176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
149276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
149376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
149476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
149576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
149676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
149776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
149876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
149976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
150076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
150176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
150276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
150376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
1504161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
15058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
15068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
15078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
15088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
15098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
15108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
15118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
15128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
15138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
15148ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
15158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
15168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
15178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
15188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
15198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
15208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
15218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
152216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
15238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
15248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
15258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
15268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
15278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
15298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
15308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
15318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
15328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
15338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
15358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
15368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
15388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
15398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
15418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
15428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
15448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
15458ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
15468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
15478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
15488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
15498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
15518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
155216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 10000, 10000,
155316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
15548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
15558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
15568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
155716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
155816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
155916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
156016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
156116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
15628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
15637db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
15648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15656e068c0182f6f85bccb855a647510724d1c65a13Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
15666e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            nodes, sLightGeometry, nullptr);
15678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
1568f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
15698ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
15708ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
15718ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
15728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
15738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1574f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
15758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
15768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
15778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
15788ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
15798ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
15808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
15818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
15825430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
15838ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
15848ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
15858ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
15868ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
15878ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
15888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
15898ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1590f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
15918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
15928ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
15938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
15948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
15958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
15968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
15978ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
15988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
15998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
16008ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
16018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
16038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
16048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
16055430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
16068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
16078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16088ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
1609f158b49c888f722194afe5a80539a2b020c130bcChris CraikTEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
16108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
16118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
16128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
16138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
16148ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
16158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
16168ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
16178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
16188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
16195430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
16208ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
16218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
16228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
16236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
16246fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
1625