FrameBuilderTests.cpp revision 04d46eb69fb4f4c4c332c36c6ae845da3b2ae848
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;
336246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craikconst std::vector< sp<RenderNode> > sEmptyNodeList;
346e068c0182f6f85bccb855a647510724d1c65a13Chris Craikconst FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
356e068c0182f6f85bccb855a647510724d1c65a13Chris Craik
3698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
376fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik/**
385854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual class implemented by each test to redirect static operation / state transitions to
395854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * virtual methods.
406fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
415854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
425854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * and allows Renderer vs Dispatching behavior to be merged.
436fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik *
446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * onXXXOp methods fail by default - tests should override ops they expect
45d3daa3198e2212c985c634821682d5819346b653Chris Craik * startRepaintLayer fails by default - tests should override if expected
466fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik * startFrame/endFrame do nothing by default - tests should override to intercept
476fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik */
485854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestRendererBase {
496fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craikpublic:
505854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    virtual ~TestRendererBase() {}
51d3daa3198e2212c985c634821682d5819346b653Chris Craik    virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
5274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        ADD_FAILURE() << "Temporary layers not expected in this test";
53a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        return nullptr;
54a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
5574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    virtual void recycleTemporaryLayer(OffscreenBuffer*) {
5674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        ADD_FAILURE() << "Temporary layers not expected in this test";
5774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    }
5898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
59a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer repaint not expected in this test";
60a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
61a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void endLayer() {
62a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << "Layer updates not expected in this test";
63a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
6498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
65e4db79de127cfe961195f52907af8451026eaa20Chris Craik    virtual void endFrame(const Rect& repaintRect) {}
665854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
6715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for single draw methods
6815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
69a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    virtual void on##Type(const Type&, const BakedOpState&) { \
70a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik        ADD_FAILURE() << #Type " not expected in this test"; \
71a6ac95e5772c5df441b49189af3a0df79a22679dChris Craik    }
727cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X)
7315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
7415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
7515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define virtual defaults for merged draw methods
7615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
7715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
7815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
7915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
807cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X)
8115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
8215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
835854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int getIndex() { return mIndex; }
845854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik
855854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikprotected:
865854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    int mIndex = 0;
875854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik};
886fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
895854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik/**
905854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik * Dispatches all static methods to similar formed methods on renderer, which fail by default but
918ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * are overridden by subclasses per test.
925854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik */
935854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass TestDispatcher {
945854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikpublic:
9515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define single op methods, which redirect to TestRendererBase
9615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
975854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
985854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik        renderer.on##Type(op, state); \
996fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    }
1007cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_RENDERABLE_OPS(X);
10115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
10215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik
10315c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    // define merged op methods, which redirect to TestRendererBase
10415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#define X(Type) \
10515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
10615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        renderer.onMerged##Type##s(opList); \
10715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik    }
1087cbf63da4f29e5a6b131796eb3b67fd9ff1521b8Chris Craik    MAP_MERGEABLE_OPS(X);
10915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik#undef X
1106fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik};
111b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1125854b34881b1a747ac80b5077869ef270a92b1f4Chris Craikclass FailRenderer : public TestRendererBase {};
1136fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1143a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simple) {
115d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleTestRenderer : public TestRendererBase {
116d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
11798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
118d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
119d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(100u, width);
120d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(200u, height);
121d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
122d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
123d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
124d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
125d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
126d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
127d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
128e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
129d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
130d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
131d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
132d3daa3198e2212c985c634821682d5819346b653Chris Craik
1338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
1348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
135ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
136b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 200, SkPaint());
137b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawBitmap(bitmap, 10, 10, nullptr);
138b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
139f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1403a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
1415854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleTestRenderer renderer;
142f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1435854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
1446fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
1456fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
1463a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
147386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    class SimpleStrokeTestRenderer : public TestRendererBase {
148386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    public:
149386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
150386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(0, mIndex++);
151386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            // even though initial bounds are empty...
152386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_TRUE(op.unmappedBounds.isEmpty())
153386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "initial bounds should be empty, since they're unstroked";
154386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
155386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik                    << "final bounds should account for stroke";
156386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        }
157386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    };
158386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
159386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    auto node = TestUtils::createNode(0, 0, 100, 200,
160386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
161386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        SkPaint strokedPaint;
162386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        strokedPaint.setStrokeWidth(10);
163386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik        canvas.drawPoint(50, 50, strokedPaint);
164386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    });
165f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 200), 100, 200,
1663a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
167386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    SimpleStrokeTestRenderer renderer;
168f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
169386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik    EXPECT_EQ(1, renderer.getIndex());
170386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik}
171386aa031793bb037ec43b6cdbd8908c343cc86cbChris Craik
1723a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
1738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
1748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
175eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
1766fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
1776fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1786fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
1796fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
180f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
1813a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
182b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1835854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
184f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
185b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
186b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
1873a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
188a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
189d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SimpleBatchingTestRenderer : public TestRendererBase {
190d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
191d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
192a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
193d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
194d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
195a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
196d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
197d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
198d3daa3198e2212c985c634821682d5819346b653Chris Craik
1998d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
2008d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
20115c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
20215c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
203b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
204b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
205b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
206eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
207a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
208b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.translate(0, 10);
209b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawRect(0, 0, 10, 10, SkPaint());
210b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik            canvas.drawBitmap(bitmap, 5, 0, nullptr);
211b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        }
212b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.restore();
213b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
214b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
215f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
2163a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
2175854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SimpleBatchingTestRenderer renderer;
218f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
219a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
22015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            << "Expect number of ops = 2 * loop count";
221a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik}
222a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik
2236246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
2246246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyNoFbo0TestRenderer : public TestRendererBase {
2256246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
2266246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
2276246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
2286246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
2296246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
2306246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
2316246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
2326246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
2336246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
2346246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // Pass empty node list, so no work is enqueued for Fbo0
2356246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
2366246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            sEmptyNodeList, sLightGeometry, Caches::getInstance());
2376246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyNoFbo0TestRenderer renderer;
2386246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2396246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
2406246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
2416246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
2426246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class EmptyWithFbo0TestRenderer : public TestRendererBase {
2436246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
2446246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
2456246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
2466246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
2476246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
2486246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
2496246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
2506246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
2516246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
2526246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
2536246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        // no drawn content
2546246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
2556246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
2566246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
2576246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // Draw, but pass empty node list, so no work is done for primary frame
2586246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
2596246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            syncedNodeList, sLightGeometry, Caches::getInstance());
2606246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EmptyWithFbo0TestRenderer renderer;
2616246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
2626246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
2636246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            " but fbo0 update lifecycle should still be observed";
2646246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
2656246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
26680d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikRENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
26780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
26880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
26980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
27080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(mIndex++, 0) << "Should be one rect";
27180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds)
27280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                    << "Last rect should occlude others.";
27380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
27480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
27580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
27680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
27780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
27880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
27980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
28080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
28180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
28280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // Damage (and therefore clip) is same as last draw, subset of renderable area.
28380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    // This means last op occludes other contents, and they'll be rejected to avoid overdraw.
28480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    SkRect damageRect = SkRect::MakeLTRB(10, 10, 190, 190);
28580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, damageRect, 200, 200,
28680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
28780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
28880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
28980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
29080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
29180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawRectsTestRenderer renderer;
29280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
29380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
29480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
29580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
29680d2ade939153da87b3cd3b0a69a713bf68b64baChris CraikRENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
29780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    static SkBitmap opaqueBitmap = TestUtils::createSkBitmap(50, 50,
29880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            SkColorType::kRGB_565_SkColorType);
29980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    static SkBitmap transpBitmap = TestUtils::createSkBitmap(50, 50,
30080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            SkColorType::kAlpha_8_SkColorType);
30180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
30280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    public:
30380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
30480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            switch(mIndex++) {
30580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 0:
30680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                EXPECT_EQ(opaqueBitmap.pixelRef(), op.bitmap->pixelRef());
30780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
30880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            case 1:
30980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                EXPECT_EQ(transpBitmap.pixelRef(), op.bitmap->pixelRef());
31080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                break;
31180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            default:
31280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik                ADD_FAILURE() << "Only two ops expected.";
31380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            }
31480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        }
31580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    };
31680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
31780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    auto node = TestUtils::createNode(0, 0, 50, 50,
31880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
31980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
32080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawRect(0, 0, 50, 50, SkPaint());
32180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
32280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
32380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        // only the below draws should remain, since they're
32480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawBitmap(opaqueBitmap, 0, 0, nullptr);
32580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik        canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
32680d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    });
32780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
32880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(50, 50), 50, 50,
32980d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
33080d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
33180d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
33280d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik            << "Recording must not have rejected ops, in order for this test to be valid";
33380d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
33480d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    AvoidOverdrawBitmapsTestRenderer renderer;
33580d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
336a82ffc549bd6dbf8cfc6f4d646d0f458dca54014sergeyv    EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
33780d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik}
33880d2ade939153da87b3cd3b0a69a713bf68b64baChris Craik
3393a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
34093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    class ClippedMergingTestRenderer : public TestRendererBase {
34193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    public:
34293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        void onMergedBitmapOps(const MergedBakedOpList& opList) override {
34393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(0, mIndex);
34493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            mIndex += opList.count;
34593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(4u, opList.count);
34693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
34793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
34893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik                    opList.clipSideFlags);
34993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        }
35093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    };
35193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    auto node = TestUtils::createNode(0, 0, 100, 100,
35293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
35393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
35493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
35593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // left side clipped (to inset left half)
35693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
35793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 0, 40, nullptr);
35893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
35993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // top side clipped (to inset top half)
36093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
36193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 0, nullptr);
36293e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
36393e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // right side clipped (to inset right half)
36493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
36593e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 80, 40, nullptr);
36693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
36793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        // bottom not clipped, just abutting (inset bottom half)
36893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
36993e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik        canvas.drawBitmap(bitmap, 40, 70, nullptr);
37093e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    });
37193e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
372f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
3733a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
37493e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    ClippedMergingTestRenderer renderer;
375f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
37693e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik    EXPECT_EQ(4, renderer.getIndex());
37793e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik}
37893e53e09dde84a5a6d6931b81198d94e2ae1c6ebChris Craik
3793a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textMerging) {
380d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    class TextMergingTestRenderer : public TestRendererBase {
381d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    public:
382d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
383d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(0, mIndex);
384d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            mIndex += opList.count;
385d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(2u, opList.count);
386d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
387d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
388d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
389d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        }
390d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    };
391d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
392d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            [](RenderProperties& props, TestCanvas& canvas) {
393d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        SkPaint paint;
394d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
395d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setAntiAlias(true);
396d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik        paint.setTextSize(50);
397dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
398dccca44ffda4836b56a21da95a046c9708ffd49csergeyv        TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
399d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    });
400f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
4013a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
402d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    TextMergingTestRenderer renderer;
403f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
404d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik    EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
405d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik}
406d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik
4073a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
408a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    const int LOOPS = 5;
409a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    class TextStrikethroughTestRenderer : public TestRendererBase {
410a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    public:
411a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
412a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik            EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
413a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
41415c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
41515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(0, mIndex);
41615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            mIndex += opList.count;
41715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            EXPECT_EQ(5u, opList.count);
418a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
419a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    };
4208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 2000,
4218d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
422a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        SkPaint textPaint;
423a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setAntiAlias(true);
424a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setTextSize(20);
425a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        textPaint.setStrikeThruText(true);
42642a5407f2c6403ea7aa7a64eaf19948dc4050df5Chris Craik        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
427a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        for (int i = 0; i < LOOPS; i++) {
428dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
429a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik        }
430a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    });
431f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 2000), 200, 2000,
4323a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
433a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    TextStrikethroughTestRenderer renderer;
434f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
435a1717271caac5e8ea3808c331d4141ac01a42134Chris Craik    EXPECT_EQ(2 * LOOPS, renderer.getIndex())
436d7448e65e243754f31890baef29dff187dc2e5e5Chris Craik            << "Expect number of ops = 2 * loop count";
437b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
438b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
4397c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craikstatic auto styles = {
4407c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
4417c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
4423a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, textStyle) {
4437c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    class TextStyleTestRenderer : public TestRendererBase {
4447c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    public:
4457c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        void onMergedTextOps(const MergedBakedOpList& opList) override {
4467c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(0, mIndex);
4477c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            ASSERT_EQ(3u, opList.count);
4487c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            mIndex += opList.count;
4497c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
4507c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            int index = 0;
4517c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            for (auto style : styles) {
4527c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                auto state = opList.states[index++];
4537c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(style, state->op->paint->getStyle())
4547c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Remainder of validation relies upon stable merged order";
4557c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                ASSERT_EQ(0, state->computedState.clipSideFlags)
4567c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                        << "Clipped bounds validation requires unclipped ops";
4577c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            }
4587c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
4597c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect fill = opList.states[0]->computedState.clippedBounds;
4607c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect stroke = opList.states[1]->computedState.clippedBounds;
4617c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
4627c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik                    << "Stroke+Fill should be same as stroke";
4637c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
4647c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_TRUE(stroke.contains(fill));
4657c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_FALSE(fill.contains(stroke));
4667c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
46779abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            // outset by half the stroke width
4687c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            Rect outsetFill(fill);
46979abbf22d4f672208327546661e694d837f564a9Derek Sollenberger            outsetFill.outset(5);
4707c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            EXPECT_EQ(stroke, outsetFill);
4717c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
4727c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    };
4737c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    auto node = TestUtils::createNode(0, 0, 400, 400,
4747c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            [](RenderProperties& props, TestCanvas& canvas) {
4757c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        SkPaint paint;
4767c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
4777c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setAntiAlias(true);
4787c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setTextSize(50);
4797c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        paint.setStrokeWidth(10);
4807c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
4817c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // draw 3 copies of the same text overlapping, each with a different style.
4827c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        // They'll get merged, but with
4837c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        for (auto style : styles) {
4847c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik            paint.setStyle(style);
485dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
4867c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik        }
4877c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    });
4887c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
4893a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
4907c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    TextStyleTestRenderer renderer;
4917c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
4927c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik    EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
4937c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik}
4947c02cab0b1c7db0fb786893240ec6f00f16c2ceeChris Craik
495aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
496aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
497d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    public:
498d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
499d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(0, mIndex++);
500e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
501d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
502d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
503d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            Matrix4 expected;
504d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            expected.loadTranslate(5, 5, 0);
505d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
506d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        }
507d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    };
508d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
509d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
510243e85b2e443def1ef47a180e824b36f513c8db8Chris Craik            SkMatrix::MakeTrans(5, 5));
511d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
512d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
513d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
514eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
515d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
516d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawLayer(layerUpdater.get());
517d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.restore();
518d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    });
519f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5203a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
521aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerClipLocalMatrixTestRenderer renderer;
522f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
523d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik    EXPECT_EQ(1, renderer.getIndex());
524d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik}
525d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik
526aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
527aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
528aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    public:
529aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
530aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_EQ(0, mIndex++);
531aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
532aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            Matrix4 expected;
533aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            expected.loadTranslate(35, 45, 0);
534aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
535aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        }
536aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    };
537aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
538aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
539aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
540aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
541aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
542aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
543aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.save(SaveFlags::MatrixClip);
544aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.translate(30, 40);
545aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
546aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.restore();
547aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
548aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
549aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
550aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
551aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    TextureLayerCombineMatricesTestRenderer renderer;
552aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
553aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    EXPECT_EQ(1, renderer.getIndex());
554aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
555aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
556aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris CraikRENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
557aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
558aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            SkMatrix::MakeTrans(5, 5));
559aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
560aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
561aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
562aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
563aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik        canvas.drawLayer(layerUpdater.get());
564aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    });
565aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
566aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
567aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    FailRenderer renderer;
568aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
569aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik}
570aafb01d8ade0def3f51b74ae3bbc610c4ab33044Chris Craik
5713a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, functor_reject) {
572223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    class FunctorTestRenderer : public TestRendererBase {
573223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    public:
574223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
575223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            EXPECT_EQ(0, mIndex++);
576223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        }
577223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    };
578223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    Functor noopFunctor;
579223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
580223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    // 1 million pixel tall view, scrolled down 80%
581223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
582223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik            [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
583223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.translate(0, -800000);
584223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik        canvas.callDrawGLFunction(&noopFunctor);
585223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    });
586223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
587223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
5883a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(scrolledFunctorView),
5893a5811b50157e7ba50854caf957e806aee794d39Chris Craik            sLightGeometry, Caches::getInstance());
590223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    FunctorTestRenderer renderer;
591223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
592223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
593223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik}
594223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik
595a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikRENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
596a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    class ColorTestRenderer : public TestRendererBase {
597a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    public:
598a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
599a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(0, mIndex++);
600a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
601a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik                    << "Color op should be expanded to bounds of surrounding";
602a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        }
603a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    };
604a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
605a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
606a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
607a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        props.setClipToBounds(false);
608a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
609a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    });
610a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
611a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
612a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            TestUtils::createSyncedNodeList(unclippedColorView),
613a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik            sLightGeometry, Caches::getInstance());
614a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    ColorTestRenderer renderer;
615a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
616a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik    EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
617a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik}
618a204848b1dc63877a12e2d24108e9d8e1e691e28Chris Craik
619a204848b1dc63877a12e2d24108e9d8e1e691e28Chris CraikTEST(FrameBuilder, renderNode) {
620d3daa3198e2212c985c634821682d5819346b653Chris Craik    class RenderNodeTestRenderer : public TestRendererBase {
621d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
622d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
623d3daa3198e2212c985c634821682d5819346b653Chris Craik            switch(mIndex++) {
624d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 0:
6255430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
626d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
627d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
628d3daa3198e2212c985c634821682d5819346b653Chris Craik            case 1:
629d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
630d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
631d3daa3198e2212c985c634821682d5819346b653Chris Craik                break;
632d3daa3198e2212c985c634821682d5819346b653Chris Craik            default:
633d3daa3198e2212c985c634821682d5819346b653Chris Craik                ADD_FAILURE();
634d3daa3198e2212c985c634821682d5819346b653Chris Craik            }
635d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
636d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
637d3daa3198e2212c985c634821682d5819346b653Chris Craik
6388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(10, 10, 110, 110,
6398d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
640b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        SkPaint paint;
641b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        paint.setColor(SK_ColorWHITE);
642b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
643b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
644b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
6458d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
646d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik            [&child](RenderProperties& props, RecordingCanvas& canvas) {
647ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkPaint paint;
648ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        paint.setColor(SK_ColorDKGRAY);
649ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawRect(0, 0, 200, 200, paint);
650ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
651eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
652ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.translate(40, 40);
653d2dfd8f128b632ed99418ab2b32949c939a9a369Chris Craik        canvas.drawRenderNode(child.get());
654ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.restore();
655b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik    });
656b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
657f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
6583a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
6595854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    RenderNodeTestRenderer renderer;
660f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
661223e3b6c2b53a66b4efd8040edfe23ed1a5c925eChris Craik    EXPECT_EQ(2, renderer.getIndex());
662b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
663b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik
6643a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, clipped) {
665d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ClippedTestRenderer : public TestRendererBase {
666d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
667d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
668d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
669d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
670e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
671d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
672d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
673d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
674d3daa3198e2212c985c634821682d5819346b653Chris Craik
6758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
6768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
677ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
678ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik        canvas.drawBitmap(bitmap, 0, 0, nullptr);
679ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik    });
680ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
681f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue,
6820b7e8245db728d127ada698be63d78b33fc6e4daChris Craik            SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
6833a5811b50157e7ba50854caf957e806aee794d39Chris Craik            200, 200, TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
6845854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    ClippedTestRenderer renderer;
685f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
686ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik}
687ddf2215d9807b641dbcb304779ef6b530f876ac7Chris Craik
6883a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
689d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerSimpleTestRenderer : public TestRendererBase {
690d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
691d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
692d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
693d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, width);
694d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(180u, height);
695d3daa3198e2212c985c634821682d5819346b653Chris Craik            return nullptr;
696d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
697d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
698d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
699d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
700d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
701d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
702d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
7035430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
704e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
705d3daa3198e2212c985c634821682d5819346b653Chris Craik
706d3daa3198e2212c985c634821682d5819346b653Chris Craik            Matrix4 expectedTransform;
707d3daa3198e2212c985c634821682d5819346b653Chris Craik            expectedTransform.loadTranslate(-10, -10, 0);
708d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
709d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
710d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
711d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
712d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
713e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
714d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
715d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
71674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
71774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
71874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(nullptr, offscreenBuffer);
71974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
720d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
721d3daa3198e2212c985c634821682d5819346b653Chris Craik
7228d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
7238d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
724eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
7256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(10, 10, 190, 190, SkPaint());
7266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
7276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
728f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
7293a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
7305854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerSimpleTestRenderer renderer;
731f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
73274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(5, renderer.getIndex());
733b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
7346fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
7353a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
736d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
737d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer2, rect2 endLayer2
738d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
739d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, layerOp1, endFrame
740d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
741d3daa3198e2212c985c634821682d5819346b653Chris Craik    class SaveLayerNestedTestRenderer : public TestRendererBase {
742d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
743d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
744d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
745d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
746d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, width);
747d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(400u, height);
748d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x400;
749d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 3) {
750d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, width);
751d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(800u, height);
752d3daa3198e2212c985c634821682d5819346b653Chris Craik                return (OffscreenBuffer*) 0x800;
753d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
754d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*) nullptr;
755d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
756d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
757d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
758d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 6);
759d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
76098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
761d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(7, mIndex++);
762d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
763e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
764d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(9, mIndex++);
765d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
766d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
767d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
768d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
7695430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
770d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 4) {
7715430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
772d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
773d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
774d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
775d3daa3198e2212c985c634821682d5819346b653Chris Craik            const int index = mIndex++;
776d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 5) {
777d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
7785430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
779d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
780d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
7815430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik                EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
782d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
783d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
78474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
78574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            const int index = mIndex++;
78674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            // order isn't important, but we need to see both
78774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            if (index == 10) {
78874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
78974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else if (index == 11) {
79074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik                EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
79174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            } else { ADD_FAILURE(); }
79274af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
793d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
794d3daa3198e2212c985c634821682d5819346b653Chris Craik
7958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(0, 0, 800, 800,
7968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
797eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
7986fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        {
7996fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.drawRect(0, 0, 800, 800, SkPaint());
800eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita            canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
8016fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            {
8026fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik                canvas.drawRect(0, 0, 400, 400, SkPaint());
8036fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            }
8046fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik            canvas.restore();
8056fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        }
8066fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
8076fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
8086fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
809f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(800, 800), 800, 800,
8103a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
8115854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    SaveLayerNestedTestRenderer renderer;
812f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
81374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(12, renderer.getIndex());
8146fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik}
8156fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
8163a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
8178d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        auto node = TestUtils::createNode(0, 0, 200, 200,
8188d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                [](RenderProperties& props, RecordingCanvas& canvas) {
819eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
8206fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
821eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
8226fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
8236fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        // draw within save layer may still be recorded, but shouldn't be drawn
8246fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.drawRect(200, 200, 400, 400, SkPaint());
8256fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
8266fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
8276fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik        canvas.restore();
8286fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    });
829f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
8303a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
8316fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
8325854b34881b1a747ac80b5077869ef270a92b1f4Chris Craik    FailRenderer renderer;
8336fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik    // should see no ops, even within the layer, since the layer should be rejected
834f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
835b565df13a9e5c7b1d7d93bdfa4a793752d66d3ccChris Craik}
8366fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik
8373a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
838b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
839b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
840b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
841b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++);
842b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
8437435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
844b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
845b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
846b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
847b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(1, mIndex++);
848b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_NE(nullptr, op.paint);
849b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
850b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
851b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
852b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(2, mIndex++);
853b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
854b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
855b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
856b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
857b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
858b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
859b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
860b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
8617435eb148e72382126e9073183e881357bb38a8bChris Craik            EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
862b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
863b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
864b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
865b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
866b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
867b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
868eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
869b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
870b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
871b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
872f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
8733a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
874b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedSimpleTestRenderer renderer;
875f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
876b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(4, renderer.getIndex());
877b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
878b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
8793a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
880b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
881b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
882b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
883b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
884b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_GT(4, index);
885b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getWidth());
886b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, op.unmappedBounds.getHeight());
887b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            if (index == 0) {
888b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
889b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 1) {
890b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
891b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 2) {
892b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
893b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            } else if (index == 3) {
894b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
895b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
896b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
897b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
898b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(4, mIndex++);
899b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            ASSERT_EQ(op.vertexCount, 16u);
900b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            for (size_t i = 0; i < op.vertexCount; i++) {
901b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                auto v = op.vertices[i];
902b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
903b87eadda1818034ce03d85f30388384d1ac65916Chris Craik                EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
904b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            }
905b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
906b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
907b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
908b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
909b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
910b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_LT(5, mIndex++);
911b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
912b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
913b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
914b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
915b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
916b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
917eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int restoreTo = canvas.save(SaveFlags::MatrixClip);
918b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.scale(2, 2);
919eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
920eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
921eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
922eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
923b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(0, 0, 100, 100, SkPaint());
924b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restoreToCount(restoreTo);
925b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
926f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
9273a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
928b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedMergedClearsTestRenderer renderer;
929f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
930b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    EXPECT_EQ(10, renderer.getIndex())
931b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
932b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
933b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
9343a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
9354876de16e34622634266d09522c9153c78c7c2fbChris Craik    class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
9364876de16e34622634266d09522c9153c78c7c2fbChris Craik    public:
9374876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
9384876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(0, mIndex++);
9394876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
9404876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
9414876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(1, mIndex++);
9424876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, op.paint);
9434876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
9444876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
9454876de16e34622634266d09522c9153c78c7c2fbChris Craik                    << "Expect dirty rect as clip";
9464876de16e34622634266d09522c9153c78c7c2fbChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
9474876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
9484876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
9494876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
9504876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
9514876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(2, mIndex++);
9524876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
9534876de16e34622634266d09522c9153c78c7c2fbChris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
9544876de16e34622634266d09522c9153c78c7c2fbChris Craik            EXPECT_EQ(3, mIndex++);
9554876de16e34622634266d09522c9153c78c7c2fbChris Craik        }
9564876de16e34622634266d09522c9153c78c7c2fbChris Craik    };
9574876de16e34622634266d09522c9153c78c7c2fbChris Craik
9584876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
9594876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
9604876de16e34622634266d09522c9153c78c7c2fbChris Craik        // save smaller than clip, so we get unclipped behavior
9614876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
9624876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(0, 0, 200, 200, SkPaint());
9634876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
9644876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
9654876de16e34622634266d09522c9153c78c7c2fbChris Craik
9664876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty, and assert we see that rect later
9674876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
9683a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
9694876de16e34622634266d09522c9153c78c7c2fbChris Craik    SaveLayerUnclippedClearClipTestRenderer renderer;
9704876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
9714876de16e34622634266d09522c9153c78c7c2fbChris Craik    EXPECT_EQ(4, renderer.getIndex());
9724876de16e34622634266d09522c9153c78c7c2fbChris Craik}
9734876de16e34622634266d09522c9153c78c7c2fbChris Craik
9743a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
9754876de16e34622634266d09522c9153c78c7c2fbChris Craik    auto node = TestUtils::createNode(0, 0, 200, 200,
9764876de16e34622634266d09522c9153c78c7c2fbChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
9774876de16e34622634266d09522c9153c78c7c2fbChris Craik        // unclipped savelayer + rect both in area that won't intersect with dirty
9784876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
9794876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.drawRect(100, 100, 200, 200, SkPaint());
9804876de16e34622634266d09522c9153c78c7c2fbChris Craik        canvas.restore();
9814876de16e34622634266d09522c9153c78c7c2fbChris Craik    });
9824876de16e34622634266d09522c9153c78c7c2fbChris Craik
9834876de16e34622634266d09522c9153c78c7c2fbChris Craik    // draw with partial screen dirty that doesn't intersect with savelayer
9844876de16e34622634266d09522c9153c78c7c2fbChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
9853a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
9864876de16e34622634266d09522c9153c78c7c2fbChris Craik    FailRenderer renderer;
9874876de16e34622634266d09522c9153c78c7c2fbChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
9884876de16e34622634266d09522c9153c78c7c2fbChris Craik}
9894876de16e34622634266d09522c9153c78c7c2fbChris Craik
990b87eadda1818034ce03d85f30388384d1ac65916Chris Craik/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
991b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
992b87eadda1818034ce03d85f30388384d1ac65916Chris Craik * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
993b87eadda1818034ce03d85f30388384d1ac65916Chris Craik */
9943a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
995b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
996b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    public:
997b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
998b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(0, mIndex++); // savelayer first
999b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            return (OffscreenBuffer*)0xabcd;
1000b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1001b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
1002b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1003b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 1 || index == 7);
1004b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1005b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
1006b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1007b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 2 || index == 8);
1008b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1009b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1010b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(3, mIndex++);
1011b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            Matrix4 expected;
1012b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            expected.loadTranslate(-100, -100, 0);
1013b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
1014b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
1015b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1016b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
1017b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            int index = mIndex++;
1018b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_TRUE(index == 4 || index == 10);
1019b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1020b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endLayer() override {
1021b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(5, mIndex++);
1022b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1023b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1024b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(6, mIndex++);
1025b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1026b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1027b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(9, mIndex++);
102874af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1029b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
1030b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        void endFrame(const Rect& repaintRect) override {
1031b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            EXPECT_EQ(11, mIndex++);
1032b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        }
103374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
103474af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(12, mIndex++);
103574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
103674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1037b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    };
1038b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1039b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
1040b87eadda1818034ce03d85f30388384d1ac65916Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1041eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
1042eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
1043eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
1044b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.drawRect(200, 200, 300, 300, SkPaint());
1045b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1046b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1047b87eadda1818034ce03d85f30388384d1ac65916Chris Craik        canvas.restore();
1048b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    });
1049f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600,
10503a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
1051b87eadda1818034ce03d85f30388384d1ac65916Chris Craik    SaveLayerUnclippedComplexTestRenderer renderer;
1052f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
105374af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(13, renderer.getIndex());
1054b87eadda1818034ce03d85f30388384d1ac65916Chris Craik}
1055b87eadda1818034ce03d85f30388384d1ac65916Chris Craik
1056f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
1057d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerSimpleTestRenderer : public TestRendererBase {
1058d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
105998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1060d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
106198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
106298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
106398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
1064d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1065d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1066d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
10670b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1068d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
1069d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Transform should be reset within layer";
1070d3daa3198e2212c985c634821682d5819346b653Chris Craik
1071e4db79de127cfe961195f52907af8451026eaa20Chris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
1072d3daa3198e2212c985c634821682d5819346b653Chris Craik                    << "Damage rect should be used to clip layer content";
1073d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1074d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1075d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(2, mIndex++);
1076d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
107798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1078d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++);
1079d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1080d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1081d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(4, mIndex++);
1082d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1083e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1084d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(5, mIndex++);
1085d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1086d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
10870b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
10888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
108916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
109016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
10910b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
10920b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
10930b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
109416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
109598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
10960b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
109798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would
109898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
109998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
11000b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
11017db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
11020b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
11030b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // only enqueue partial damage
110498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
11050b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
11060b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1107f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
11083a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedNodeList, sLightGeometry, Caches::getInstance());
11090b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerSimpleTestRenderer renderer;
1110f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
11110b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    EXPECT_EQ(6, renderer.getIndex());
11120b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
11130b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
111498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
11150b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
11160b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1117f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
1118d3daa3198e2212c985c634821682d5819346b653Chris Craik    /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
1119d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(child), rect(grey), endLayer
1120d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startTemporaryLayer, drawLayer(child), endLayer
1121d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
1122d3daa3198e2212c985c634821682d5819346b653Chris Craik     * - startFrame, drawLayer(parent), endLayerb
1123d3daa3198e2212c985c634821682d5819346b653Chris Craik     */
1124d3daa3198e2212c985c634821682d5819346b653Chris Craik    class HwLayerComplexTestRenderer : public TestRendererBase {
1125d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1126d3daa3198e2212c985c634821682d5819346b653Chris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
1127d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(3, mIndex++); // savelayer first
1128d3daa3198e2212c985c634821682d5819346b653Chris Craik            return (OffscreenBuffer*)0xabcd;
1129d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
113098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1131d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1132d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 0) {
1133d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting inner layer
113498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
113598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
1136d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 6) {
1137d3daa3198e2212c985c634821682d5819346b653Chris Craik                // starting outer layer
113898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
113998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
1140d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1141d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1142d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1143d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1144d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 1) {
1145d3daa3198e2212c985c634821682d5819346b653Chris Craik                // inner layer's rect (white)
1146d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
1147d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 7) {
1148d3daa3198e2212c985c634821682d5819346b653Chris Craik                // outer layer's rect (grey)
1149d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1150d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1151d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1152d3daa3198e2212c985c634821682d5819346b653Chris Craik        void endLayer() override {
1153d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1154d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_TRUE(index == 2 || index == 5 || index == 9);
1155d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
115698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
1157d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(10, mIndex++);
1158d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1159d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
116098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            OffscreenBuffer* layer = *op.layerHandle;
1161d3daa3198e2212c985c634821682d5819346b653Chris Craik            int index = mIndex++;
1162d3daa3198e2212c985c634821682d5819346b653Chris Craik            if (index == 4) {
116398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportWidth);
116498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(100u, layer->viewportHeight);
1165d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 8) {
1166d3daa3198e2212c985c634821682d5819346b653Chris Craik                EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
1167d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else if (index == 11) {
116898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportWidth);
116998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik                EXPECT_EQ(200u, layer->viewportHeight);
1170d3daa3198e2212c985c634821682d5819346b653Chris Craik            } else { ADD_FAILURE(); }
1171d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1172e4db79de127cfe961195f52907af8451026eaa20Chris Craik        void endFrame(const Rect& repaintRect) override {
1173d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(12, mIndex++);
1174d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
117574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
117674af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(13, mIndex++);
117774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
1178d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1179d3daa3198e2212c985c634821682d5819346b653Chris Craik
118016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto child = TestUtils::createNode(50, 50, 150, 150,
118116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
118216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
11830b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
11840b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorWHITE);
11850b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
118616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
118798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
118898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(child->getLayerHandle()) = &childLayer;
11890b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
11900b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    RenderNode* childPtr = child.get();
119116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 200, 200,
119216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
119316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
11940b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        SkPaint paint;
11950b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        paint.setColor(SK_ColorDKGRAY);
11960b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRect(0, 0, 200, 200, paint);
11970b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1198eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
11990b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.drawRenderNode(childPtr);
12000b7e8245db728d127ada698be63d78b33fc6e4daChris Craik        canvas.restore();
120116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
120298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
120398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *(parent->getLayerHandle()) = &parentLayer;
12040b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12057db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
12060b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
120798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
12080b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
12090b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
12100b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
1211f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
12123a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedList, sLightGeometry, Caches::getInstance());
12130b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    HwLayerComplexTestRenderer renderer;
1214f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
121574af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(14, renderer.getIndex());
12160b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12170b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    // clean up layer pointers, so we can safely destruct RenderNodes
12180b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(child->getLayerHandle()) = nullptr;
12190b7e8245db728d127ada698be63d78b33fc6e4daChris Craik    *(parent->getLayerHandle()) = nullptr;
12200b7e8245db728d127ada698be63d78b33fc6e4daChris Craik}
12210b7e8245db728d127ada698be63d78b33fc6e4daChris Craik
12226246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12236246d27813f25b85f6e4b5cb1121fe8484bcce2dChris CraikRENDERTHREAD_TEST(FrameBuilder, buildLayer) {
12246246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    class BuildLayerTestRenderer : public TestRendererBase {
12256246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    public:
12266246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
12276246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(0, mIndex++);
12286246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
12296246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
12306246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
12316246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
12326246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
12336246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(1, mIndex++);
12346246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12356246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity())
12366246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Transform should be reset within layer";
12376246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12386246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
12396246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik                    << "Damage rect should be used to clip layer content";
12406246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
12416246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endLayer() override {
12426246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            EXPECT_EQ(2, mIndex++);
12436246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
12446246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
12456246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
12466246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
12476246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        void endFrame(const Rect& repaintRect) override {
12486246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            ADD_FAILURE() << "Primary frame draw not expected in this test";
12496246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        }
12506246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    };
12516246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12526246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    auto node = TestUtils::createNode(10, 10, 110, 110,
12536246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
12546246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        props.mutateLayerProperties().setType(LayerType::RenderLayer);
12556246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
12566246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    });
12576246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer** layerHandle = node->getLayerHandle();
12586246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12596246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // create RenderNode's layer here in same way prepareTree would
12606246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
12616246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = &layer;
12626246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12636246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    auto syncedNodeList = TestUtils::createSyncedNodeList(node);
12646246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12656246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // only enqueue partial damage
12666246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
12676246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
12686246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12696246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // Draw, but pass empty node list, so no work is done for primary frame
12706246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(1, 1), 1, 1,
12716246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik            sEmptyNodeList, sLightGeometry, Caches::getInstance());
12726246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    BuildLayerTestRenderer renderer;
12736246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
12746246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    EXPECT_EQ(3, renderer.getIndex());
12756246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
12766246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
12776246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik    *layerHandle = nullptr;
12786246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik}
12796246d27813f25b85f6e4b5cb1121fe8484bcce2dChris Craik
1280161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
1281161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    SkPaint paint;
1282161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    paint.setColor(SkColorSetARGB(256, 0, 0, expectedDrawOrder)); // order put in blue channel
1283161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRect(0, 0, 100, 100, paint);
1284161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
1285161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craikstatic void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
128616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
12878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
1288161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, expectedDrawOrder);
1289161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1290161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->mutateStagingProperties().setTranslationZ(z);
1291161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
1292161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
1293161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik}
12943a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, zReorder) {
1295d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ZReorderTestRenderer : public TestRendererBase {
1296d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1297d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1298d3daa3198e2212c985c634821682d5819346b653Chris Craik            int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
1299d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
1300d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1301d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1302d3daa3198e2212c985c634821682d5819346b653Chris Craik
130316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto parent = TestUtils::createNode(0, 0, 100, 100,
13048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
1305161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1306161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 1);
1307161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(true);
1308161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 6, 2.0f);
1309161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 3);
1310161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 4, 0.0f);
1311161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 5);
1312161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 2, -2.0f);
1313161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 7, 2.0f);
1314161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        canvas.insertReorderBarrier(false);
1315161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedRect(&canvas, 8);
1316161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
1317161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    });
1318f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
13193a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
1320161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    ZReorderTestRenderer renderer;
1321f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1322161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik    EXPECT_EQ(10, renderer.getIndex());
1323161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik};
1324161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
13253a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
13268d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollX = 5;
13278d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    static const int scrollY = 10;
13288d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    class ProjectionReorderTestRenderer : public TestRendererBase {
13298d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    public:
13308d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
13318d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            const int index = mIndex++;
13328d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
13338d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            Matrix4 expectedMatrix;
13348d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            switch (index) {
13358d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 0:
13368d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
13378d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
13388d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadIdentity();
1339678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
13408d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
13418d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 1:
13428d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
13438d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
1344678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
1345678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1346678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(Rect(-35, -30, 45, 50),
1347678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                        Rect(state.computedState.localProjectionPathMask->getBounds()));
13488d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
13498d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            case 2:
13508d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
13518d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
13528d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
1353678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
13548d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                break;
13558d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            default:
13568d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik                ADD_FAILURE();
13578d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            }
1358678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expectedMatrix, state.computedState.transform);
13598d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        }
13608d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    };
13618d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
13628d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    /**
13638d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
13648d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
13658d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * draw, but because it is projected backwards, it's drawn in between B and C.
13668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     *
13678d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * The parent is scrolled by scrollX/scrollY, but this does not affect the background
13688d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     * (which isn't affected by scroll).
13698d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik     */
13708d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
13718d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
13728d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectionReceiver(true);
13738d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
13748d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
13758d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationX(scrollX);
13768d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setTranslationY(scrollY);
13778d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
13788d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
13798d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorWHITE);
13808d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 100, paint);
13818d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
13828d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
13838d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
13848d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setProjectBackwards(true);
13858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        properties.setClipToBounds(false);
13868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
13878d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorDKGRAY);
13888d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(-10, -10, 60, 60, paint);
13898d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
13908d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto child = TestUtils::createNode(0, 50, 100, 100,
13918d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
13928d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        SkPaint paint;
13938d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        paint.setColor(SK_ColorBLUE);
13948d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRect(0, 0, 100, 50, paint);
13958d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(projectingRipple.get());
13968d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
13978d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 100, 100,
13988d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1399678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1400678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
1401678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1402eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
14038d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
14048d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(receiverBackground.get());
14058d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.drawRenderNode(child.get());
14068d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        canvas.restore();
14078d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    });
14088d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1409f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
14103a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
14118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    ProjectionReorderTestRenderer renderer;
1412f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
14138d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    EXPECT_EQ(3, renderer.getIndex());
14148d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik}
14158d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik
1416678ff81105753656aa4822f4f675ef96dc9d2b83Chris CraikRENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
1417678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollX = 5;
1418678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    static const int scrollY = 10;
1419678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    class ProjectionHwLayerTestRenderer : public TestRendererBase {
1420678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    public:
1421678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
1422678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(0, mIndex++);
1423678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1424678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
1425678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(1, mIndex++);
1426678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1427678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1428678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void endLayer() override {
1429678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(2, mIndex++);
1430678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1431678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1432678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(3, mIndex++);
1433678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1434678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1435678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1436678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(4, mIndex++);
1437678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
1438678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            Matrix4 expected;
1439678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
1440678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(expected, state.computedState.transform);
1441678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(Rect(-85, -80, 295, 300),
1442678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik                    Rect(state.computedState.localProjectionPathMask->getBounds()));
1443678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1444678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
1445678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            EXPECT_EQ(5, mIndex++);
1446678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
1447678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        }
1448678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    };
1449678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1450678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1451678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectionReceiver(true);
1452678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1453678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1454678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationX(scrollX);
1455678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setTranslationY(scrollY);
1456678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1457678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1458678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1459678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1460678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1461678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setProjectBackwards(true);
1462678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.setClipToBounds(false);
1463678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
1464678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1465678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto child = TestUtils::createNode(100, 100, 300, 300,
1466678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1467678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
1468678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(projectingRipple.get());
1469678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
1470678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1471678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1472678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1473678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        // Set a rect outline for the projecting ripple to be masked against.
1474678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
1475678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1476678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(receiverBackground.get());
1477678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik        canvas.drawRenderNode(child.get());
1478678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    });
1479678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1480678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer** layerHandle = child->getLayerHandle();
1481678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1482678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
1483678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
1484678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    Matrix4 windowTransform;
1485678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
1486678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layer.setWindowTransform(windowTransform);
1487678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = &layer;
1488678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1489678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    auto syncedList = TestUtils::createSyncedNodeList(parent);
1490678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
1491678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
1492678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
14933a5811b50157e7ba50854caf957e806aee794d39Chris Craik            syncedList, sLightGeometry, Caches::getInstance());
1494678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    ProjectionHwLayerTestRenderer renderer;
1495678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1496678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    EXPECT_EQ(6, renderer.getIndex());
1497678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1498678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    // clean up layer pointer, so we can safely destruct RenderNode
1499678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik    *layerHandle = nullptr;
1500678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik}
1501678ff81105753656aa4822f4f675ef96dc9d2b83Chris Craik
1502a748c08241e43fc68c7c34767d819aef5183936eChris CraikRENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
1503a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollX = 500000;
1504a748c08241e43fc68c7c34767d819aef5183936eChris Craik    static const int scrollY = 0;
1505a748c08241e43fc68c7c34767d819aef5183936eChris Craik    class ProjectionChildScrollTestRenderer : public TestRendererBase {
1506a748c08241e43fc68c7c34767d819aef5183936eChris Craik    public:
1507a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1508a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(0, mIndex++);
1509a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1510a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1511a748c08241e43fc68c7c34767d819aef5183936eChris Craik        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
1512a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_EQ(1, mIndex++);
1513a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_NE(nullptr, state.computedState.clipState);
1514a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
1515a748c08241e43fc68c7c34767d819aef5183936eChris Craik            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
1516a748c08241e43fc68c7c34767d819aef5183936eChris Craik            EXPECT_TRUE(state.computedState.transform.isIdentity());
1517a748c08241e43fc68c7c34767d819aef5183936eChris Craik        }
1518a748c08241e43fc68c7c34767d819aef5183936eChris Craik    };
1519a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
1520a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1521a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectionReceiver(true);
1522a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRect(0, 0, 400, 400, SkPaint());
1523a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1524a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
1525a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [](RenderProperties& properties, RecordingCanvas& canvas) {
1526a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // scroll doesn't apply to background, so undone via translationX/Y
1527a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
1528a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationX(scrollX);
1529a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setTranslationY(scrollY);
1530a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setProjectBackwards(true);
1531a748c08241e43fc68c7c34767d819aef5183936eChris Craik        properties.setClipToBounds(false);
1532a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawOval(0, 0, 200, 200, SkPaint());
1533a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1534a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto child = TestUtils::createNode(0, 0, 400, 400,
1535a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
1536a748c08241e43fc68c7c34767d819aef5183936eChris Craik        // Record time clip will be ignored by projectee
1537a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
1538a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1539a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
1540a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(projectingRipple.get());
1541a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1542a748c08241e43fc68c7c34767d819aef5183936eChris Craik    auto parent = TestUtils::createNode(0, 0, 400, 400,
1543a748c08241e43fc68c7c34767d819aef5183936eChris Craik            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
1544a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(receiverBackground.get());
1545a748c08241e43fc68c7c34767d819aef5183936eChris Craik        canvas.drawRenderNode(child.get());
1546a748c08241e43fc68c7c34767d819aef5183936eChris Craik    });
1547a748c08241e43fc68c7c34767d819aef5183936eChris Craik
1548a748c08241e43fc68c7c34767d819aef5183936eChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
15493a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
1550a748c08241e43fc68c7c34767d819aef5183936eChris Craik    ProjectionChildScrollTestRenderer renderer;
1551a748c08241e43fc68c7c34767d819aef5183936eChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
1552a748c08241e43fc68c7c34767d819aef5183936eChris Craik    EXPECT_EQ(2, renderer.getIndex());
1553a748c08241e43fc68c7c34767d819aef5183936eChris Craik}
1554a748c08241e43fc68c7c34767d819aef5183936eChris Craik
155598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik// creates a 100x100 shadow casting node with provided translationZ
155698787e6c9b2c10b1ab7820bdac168686025b924aChris Craikstatic sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
155716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    return TestUtils::createNode(0, 0, 100, 100,
15588d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
155916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.setTranslationZ(translationZ);
156016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
156198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        SkPaint paint;
156298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        paint.setColor(SK_ColorWHITE);
156398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
156498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
156598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
156698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
15676e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadow) {
1568d3daa3198e2212c985c634821682d5819346b653Chris Craik    class ShadowTestRenderer : public TestRendererBase {
1569d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1570d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
1571d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(0, mIndex++);
157298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
15736e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
15746e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
157598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
157698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            Matrix4 expectedZ;
157798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            expectedZ.loadTranslate(0, 0, 5);
15786e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
1579d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1580d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1581d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(1, mIndex++);
1582d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1583d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1584161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
15858d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
15868d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
158798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
158898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
1589d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
159098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1591f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
15923a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(parent), sLightGeometry, Caches::getInstance());
159398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowTestRenderer renderer;
1594f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
159598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(2, renderer.getIndex());
159698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
159798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
15986e068c0182f6f85bccb855a647510724d1c65a13Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
159998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowSaveLayerTestRenderer : public TestRendererBase {
160098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
160198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
160298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
160398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            return nullptr;
160498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
160598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
160698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
16076e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
16086e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
160998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
161098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
161198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
161298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
161398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
161498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
161598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
161698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
161798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
161898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
161974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
162074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(5, mIndex++);
162174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
162298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
162398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
16248d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
16258d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
162698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        // save/restore outside of reorderBarrier, so they don't get moved out of place
162798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
1628eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
1629d3daa3198e2212c985c634821682d5819346b653Chris Craik        canvas.insertReorderBarrier(true);
163098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
163198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(false);
163298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restoreToCount(count);
1633d3daa3198e2212c985c634821682d5819346b653Chris Craik    });
1634d3daa3198e2212c985c634821682d5819346b653Chris Craik
1635f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
16366e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
16373a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
163898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowSaveLayerTestRenderer renderer;
1639f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
164074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    EXPECT_EQ(6, renderer.getIndex());
164198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
1642d3daa3198e2212c985c634821682d5819346b653Chris Craik
1643f158b49c888f722194afe5a80539a2b020c130bcChris CraikRENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
164498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowHwLayerTestRenderer : public TestRendererBase {
164598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
164698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
164798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(0, mIndex++);
164898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
164998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
165098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(1, mIndex++);
16516e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
16526e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
16536e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
165498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
165598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
165698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(2, mIndex++);
165798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
165898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void endLayer() override {
165998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(3, mIndex++);
166098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
166198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
166298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_EQ(4, mIndex++);
166398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
166498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
1665d3daa3198e2212c985c634821682d5819346b653Chris Craik
16668d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(50, 60, 150, 160,
166716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [](RenderProperties& props, RecordingCanvas& canvas) {
166816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.mutateLayerProperties().setType(LayerType::RenderLayer);
166998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
1670eecff56fed5dd5206acfbc5007b4912081b36d3bFlorin Malita        canvas.save(SaveFlags::MatrixClip);
167198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.translate(20, 10);
167298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
167398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.restore();
167416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
167598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer** layerHandle = parent->getLayerHandle();
167698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
167798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
167898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
167998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    Matrix4 windowTransform;
168098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
168198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layer.setWindowTransform(windowTransform);
168298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = &layer;
168398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
16847db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto syncedList = TestUtils::createSyncedNodeList(parent);
168598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
168698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
1687f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
16886e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            syncedList,
16893a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
169098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowHwLayerTestRenderer renderer;
1691f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
169298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(5, renderer.getIndex());
169398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
169498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    // clean up layer pointer, so we can safely destruct RenderNode
169598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    *layerHandle = nullptr;
1696d3daa3198e2212c985c634821682d5819346b653Chris Craik}
169776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
16983a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
169998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    class ShadowLayeringTestRenderer : public TestRendererBase {
170098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    public:
170198787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
170298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
170398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 0 || index == 1);
170498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
170598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
170698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            int index = mIndex++;
170798787e6c9b2c10b1ab7820bdac168686025b924aChris Craik            EXPECT_TRUE(index == 2 || index == 3);
170898787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        }
170998787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    };
17108d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik    auto parent = TestUtils::createNode(0, 0, 200, 200,
17118d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
171298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.insertReorderBarrier(true);
171398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
171498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik        canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
171598787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    });
171698787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
1717f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
17186e068c0182f6f85bccb855a647510724d1c65a13Chris Craik            TestUtils::createSyncedNodeList(parent),
17193a5811b50157e7ba50854caf957e806aee794d39Chris Craik            (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
172098787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    ShadowLayeringTestRenderer renderer;
1721f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
172298787e6c9b2c10b1ab7820bdac168686025b924aChris Craik    EXPECT_EQ(4, renderer.getIndex());
172398787e6c9b2c10b1ab7820bdac168686025b924aChris Craik}
172498787e6c9b2c10b1ab7820bdac168686025b924aChris Craik
172516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckstatic void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
172676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
1727d3daa3198e2212c985c634821682d5819346b653Chris Craik    class PropertyTestRenderer : public TestRendererBase {
1728d3daa3198e2212c985c634821682d5819346b653Chris Craik    public:
1729d3daa3198e2212c985c634821682d5819346b653Chris Craik        PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
1730d3daa3198e2212c985c634821682d5819346b653Chris Craik                : mCallback(callback) {}
1731d3daa3198e2212c985c634821682d5819346b653Chris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
1732d3daa3198e2212c985c634821682d5819346b653Chris Craik            EXPECT_EQ(mIndex++, 0);
1733d3daa3198e2212c985c634821682d5819346b653Chris Craik            mCallback(op, state);
1734d3daa3198e2212c985c634821682d5819346b653Chris Craik        }
1735d3daa3198e2212c985c634821682d5819346b653Chris Craik        std::function<void(const RectOp&, const BakedOpState&)> mCallback;
1736d3daa3198e2212c985c634821682d5819346b653Chris Craik    };
1737d3daa3198e2212c985c634821682d5819346b653Chris Craik
173816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 100, 100,
173916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
174016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(props);
174176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkPaint paint;
174276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        paint.setColor(SK_ColorWHITE);
174376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        canvas.drawRect(0, 0, 100, 100, paint);
174416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
174576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
1746f158b49c888f722194afe5a80539a2b020c130bcChris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
17473a5811b50157e7ba50854caf957e806aee794d39Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
174876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    PropertyTestRenderer renderer(opValidateCallback);
1749f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
175076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
175176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
175276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
17533a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
175476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
175576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAlpha(0.5f);
175676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setHasOverlappingRendering(false);
175776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
175876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
175976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
176076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
176176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
17623a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
176376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
176476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipToBounds(true);
176576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setClipBounds(Rect(10, 20, 300, 400));
176676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
176776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
176876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Clip rect should be intersection of node bounds and clip bounds";
176976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
177076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
177176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
17723a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
177376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
177476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableRevealClip().set(true, 50, 50, 25);
177576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
177676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
177776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_TRUE(state.roundRectClipState->highPriority);
177876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(25, state.roundRectClipState->radius);
177976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
178076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
178176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
178276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
17833a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
178476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
178576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setShouldClip(true);
178676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
178776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
178876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        ASSERT_NE(nullptr, state.roundRectClipState);
178976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_FALSE(state.roundRectClipState->highPriority);
179076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(5, state.roundRectClipState->radius);
179176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
179276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
179376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
179476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
17953a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
179676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    testProperty([](RenderProperties& properties) {
179776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setLeftTopRightBottom(10, 10, 110, 110);
179876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
179976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
180076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setStaticMatrix(&staticMatrix);
180176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
180276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignored, since static overrides animation
180376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
180476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setAnimationMatrix(&animationMatrix);
180576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
180676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationX(10);
180776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setTranslationY(20);
180876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleX(0.5f);
180976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        properties.setScaleY(0.7f);
181076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    }, [](const RectOp& op, const BakedOpState& state) {
181176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        Matrix4 matrix;
181276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.loadTranslate(10, 10, 0); // left, top
181376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(1.2f, 1.2f, 1); // static matrix
181476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // ignore animation matrix, since static overrides it
181576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
181676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // translation xy
181776caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(10, 20);
181876caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik
181976caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        // scale xy (from default pivot - center)
182076caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(50, 50);
182176caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.scale(0.5f, 0.7f, 1);
182276caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        matrix.translate(-50, -50);
182376caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik        EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
182476caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik                << "Op draw matrix must match expected combination of transformation properties";
182576caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik    });
182676caecf421b42e9b8294a65f62ff2d90b55a337bChris Craik}
1827161f54b2d4160b8d3f3da9eba5746da5162e4821Chris Craik
18288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikstruct SaveLayerAlphaData {
18298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerWidth = 0;
18308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    uint32_t layerHeight = 0;
18318ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Rect rectClippedBounds;
18328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 rectMatrix;
18338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik};
18348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik/**
18358ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Constructs a view to hit the temporary layer alpha property implementation:
18368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     a) 0 < alpha < 1
18378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     b) too big for layer (larger than maxTextureSize)
18388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *     c) overlapping rendering content
18398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * returning observed data about layer size and content clip/transform.
18408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik *
18418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
18428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik * (for efficiency, and to fit in layer size constraints) based on parent clip.
18438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik */
18448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craikvoid testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
184516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        std::function<void(RenderProperties&)> propSetupCallback) {
18468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
18478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    public:
18488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
18498ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik                : mOutData(outData) {}
18508ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
18518ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
18528ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(0, mIndex++);
18538ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerWidth = width;
18548ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->layerHeight = height;
18558ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            return nullptr;
18568ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
18578ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onRectOp(const RectOp& op, const BakedOpState& state) override {
18588ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(1, mIndex++);
18598ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
18608ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectClippedBounds = state.computedState.clippedBounds;
18618ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            mOutData->rectMatrix = state.computedState.transform;
18628ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
18638ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void endLayer() override {
18648ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(2, mIndex++);
18658ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
18668ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
18678ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            EXPECT_EQ(3, mIndex++);
18688ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        }
186974af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
187074af6e282f8a8f75928a071e8200039517cf5c12Chris Craik            EXPECT_EQ(4, mIndex++);
187174af6e282f8a8f75928a071e8200039517cf5c12Chris Craik        }
18728ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    private:
18738ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        SaveLayerAlphaData* mOutData;
18748ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    };
18758ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
18768ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
18778ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "Node must be bigger than max texture size to exercise saveLayer codepath";
187816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    auto node = TestUtils::createNode(0, 0, 10000, 10000,
187916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
18808ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setHasOverlappingRendering(true);
18818ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
18828ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // apply other properties
188316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        propSetupCallback(properties);
188416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
188516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        SkPaint paint;
188616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        paint.setColor(SK_ColorWHITE);
188716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        canvas.drawRect(0, 0, 10000, 10000, paint);
18888ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
18897db5ffb7dbd30202468459e2ef4426e91d4fcbb3John Reck    auto nodes = TestUtils::createSyncedNodeList(node); // sync before querying height
18908ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
18916e068c0182f6f85bccb855a647510724d1c65a13Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
18923a5811b50157e7ba50854caf957e806aee794d39Chris Craik            nodes, sLightGeometry, Caches::getInstance());
18938ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
1894f158b49c888f722194afe5a80539a2b020c130bcChris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
18958ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
18968ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // assert, since output won't be valid if we haven't seen a save layer triggered
189774af6e282f8a8f75928a071e8200039517cf5c12Chris Craik    ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
18988ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
18998ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
19003a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
19018ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
19028ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
19038ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(10); // offset rendering content
19048ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(-2000); // offset rendering content
19058ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
19068ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(190u, observedData.layerWidth);
19078ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(200u, observedData.layerHeight);
19085430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
19098ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be clipped to screen area";
19108ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    Matrix4 expected;
19118ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    expected.loadTranslate(0, -2000, 0);
19128ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
19138ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik            << "expect content to be translated as part of being clipped";
19148ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
19158ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
19163a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
19178ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
19188ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
19198ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // Translate and rotate the view so that the only visible part is the top left corner of
19208d1f2120fe80b23ab03c7168e3b6b2d13bafe2e7Chris Craik        // the view. It will form an isosceles right triangle with a long side length of 200 at the
19218ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        // bottom of the viewport.
19228ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationX(100);
19238ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setTranslationY(100);
19248ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
19258ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
19268ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setRotation(45);
19278ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
19288ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    // ceil(sqrt(2) / 2 * 200) = 142
19298ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerWidth);
19308ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(142u, observedData.layerHeight);
19315430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
19328ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
19338ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
19348ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
19353a5811b50157e7ba50854caf957e806aee794d39Chris CraikRENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
19368ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    SaveLayerAlphaData observedData;
19378ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
19388ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotX(0);
19398ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setPivotY(0);
19408ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleX(2);
19418ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik        properties.setScaleY(0.5f);
19428ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    });
19438ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(100u, observedData.layerWidth);
19448ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_EQ(400u, observedData.layerHeight);
19455430ab220b231a96b71c3e030d0303d9ce008b05Chris Craik    EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
19468ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
19478ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik}
19488ecf41c61a5185207a21d64681e8ebc2502b7b2aChris Craik
194904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris CraikRENDERTHREAD_TEST(FrameBuilder, clip_replace) {
195004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    class ClipReplaceTestRenderer : public TestRendererBase {
195104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    public:
195204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
195304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(0, mIndex++);
195404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_TRUE(op.localClip->intersectWithRoot);
195504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            EXPECT_EQ(Rect(20, 10, 30, 40), state.computedState.clipState->rect)
195604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik                    << "Expect resolved clip to be intersection of viewport clip and clip op";
195704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        }
195804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    };
195904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    auto node = TestUtils::createNode(20, 20, 30, 30,
196004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            [](RenderProperties& props, RecordingCanvas& canvas) {
196104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        canvas.clipRect(0, -20, 10, 30, SkRegion::kReplace_Op);
196204d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
196304d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    });
196404d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
196504d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
196604d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik            TestUtils::createSyncedNodeList(node), sLightGeometry, Caches::getInstance());
196704d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    ClipReplaceTestRenderer renderer;
196804d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
196904d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik    EXPECT_EQ(1, renderer.getIndex());
197004d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik}
197104d46eb69fb4f4c4c332c36c6ae845da3b2ae848Chris Craik
19726fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace uirenderer
19736fe991e5e76f9af9dab960100d5768d96d5f4daaChris Craik} // namespace android
1974