RenderNodeDrawableTests.cpp revision 52771272f4f018f4fc6846224bf047497e784af1
1021693b967a2c5556dddd183eb0247df4079e1adStan Iliev/*
2021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * Copyright (C) 2016 The Android Open Source Project
3021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *
4021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * Licensed under the Apache License, Version 2.0 (the "License");
5021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * you may not use this file except in compliance with the License.
6021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * You may obtain a copy of the License at
7021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *
8021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *      http://www.apache.org/licenses/LICENSE-2.0
9021693b967a2c5556dddd183eb0247df4079e1adStan Iliev *
10021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * Unless required by applicable law or agreed to in writing, software
11021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * distributed under the License is distributed on an "AS IS" BASIS,
12021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * See the License for the specific language governing permissions and
14021693b967a2c5556dddd183eb0247df4079e1adStan Iliev * limitations under the License.
15021693b967a2c5556dddd183eb0247df4079e1adStan Iliev */
16021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
17021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <gtest/gtest.h>
18021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <VectorDrawable.h>
19021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
20021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "AnimationContext.h"
21021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "DamageAccumulator.h"
22021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "IContextFactory.h"
23021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "pipeline/skia/SkiaDisplayList.h"
24db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev#include "pipeline/skia/SkiaPipeline.h"
25021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "pipeline/skia/SkiaRecordingCanvas.h"
26021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "renderthread/CanvasContext.h"
27021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "tests/common/TestUtils.h"
28021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include "SkiaCanvas.h"
29db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev#include <SkSurface_Base.h>
30021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <SkLiteRecorder.h>
31db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev#include <SkClipStack.h>
3252771272f4f018f4fc6846224bf047497e784af1Stan Iliev#include "FatalTestCanvas.h"
33021693b967a2c5556dddd183eb0247df4079e1adStan Iliev#include <string.h>
34021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
35021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
36021693b967a2c5556dddd183eb0247df4079e1adStan Ilievusing namespace android;
37021693b967a2c5556dddd183eb0247df4079e1adStan Ilievusing namespace android::uirenderer;
38021693b967a2c5556dddd183eb0247df4079e1adStan Ilievusing namespace android::uirenderer::renderthread;
39021693b967a2c5556dddd183eb0247df4079e1adStan Ilievusing namespace android::uirenderer::skiapipeline;
40021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
41021693b967a2c5556dddd183eb0247df4079e1adStan IlievTEST(RenderNodeDrawable, create) {
42021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    auto rootNode = TestUtils::createNode(0, 0, 200, 400,
43021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            [](RenderProperties& props, Canvas& canvas) {
44021693b967a2c5556dddd183eb0247df4079e1adStan Iliev                canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
45021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            });
46021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
47021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    auto skLiteDL = SkLiteDL::New(SkRect::MakeWH(1, 1));
48021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkLiteRecorder canvas;
49021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas.reset(skLiteDL.get());
50021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas.translate(100, 100);
51021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    RenderNodeDrawable drawable(rootNode.get(), &canvas);
52021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
53021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    ASSERT_EQ(drawable.getRenderNode(), rootNode.get());
54021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    ASSERT_EQ(&drawable.getNodeProperties(), &rootNode->properties());
55021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    ASSERT_EQ(drawable.getRecordedMatrix(), canvas.getTotalMatrix());
56021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
57021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
58db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievnamespace {
59db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
602f06e8ad1a1c4d0866bb66854d2759e275898635Stan Ilievstatic void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
612f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    SkPaint paint;
622f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    // order put in blue channel, transparent so overlapped content doesn't get rejected
632f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
642f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    canvas->drawRect(0, 0, 100, 100, paint);
65021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
66021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
672f06e8ad1a1c4d0866bb66854d2759e275898635Stan Ilievstatic void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
682f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    auto node = TestUtils::createSkiaNode(0, 0, 100, 100,
692f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev            [expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) {
702f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedRect(&canvas, expectedDrawOrder);
712f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        props.setTranslationZ(z);
722f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    });
732f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
742f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev}
75021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
76db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievstatic void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder,
77db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup) {
78db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto node = TestUtils::createSkiaNode(0, 0, 100, 100,
79db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [expectedDrawOrder, setup](RenderProperties& props, SkiaRecordingCanvas& canvas) {
80db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedRect(&canvas, expectedDrawOrder);
81db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        if (setup) {
82db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             setup(props, canvas);
832f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        }
84db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    });
85db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
86db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
87db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
88db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievclass ZReorderCanvas : public SkCanvas {
89db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievpublic:
90db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderCanvas(int width, int height) : SkCanvas(width, height) {}
91db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
92db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
9352771272f4f018f4fc6846224bf047497e784af1Stan Iliev        EXPECT_EQ(expectedOrder, mDrawCounter++) << "An op was drawn out of order";
94db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }
9552771272f4f018f4fc6846224bf047497e784af1Stan Iliev    int getIndex() { return mDrawCounter; }
96db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievprotected:
9752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    int mDrawCounter = 0;
98db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev};
99db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
100db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev} // end anonymous namespace
101db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
102db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievTEST(RenderNodeDrawable, zReorder) {
1032f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev
1042f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
1052f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
106347691f8d87157be0eaeca26f4003d8a06a275e3Stan Iliev        canvas.insertReorderBarrier(true);
107347691f8d87157be0eaeca26f4003d8a06a275e3Stan Iliev        canvas.insertReorderBarrier(false);
1082f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
1092f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedRect(&canvas, 1);
1102f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        canvas.insertReorderBarrier(true);
1112f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedNode(&canvas, 6, 2.0f);
1122f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedRect(&canvas, 3);
1132f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedNode(&canvas, 4, 0.0f);
1142f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedRect(&canvas, 5);
1152f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedNode(&canvas, 2, -2.0f);
1162f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedNode(&canvas, 7, 2.0f);
1172f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        canvas.insertReorderBarrier(false);
1182f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedRect(&canvas, 8);
1192f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev        drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
12088e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
12188e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedRect(&canvas, 11);
12288e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedNode(&canvas, 10, -1.0f);
12388e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(false);
12488e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true); //test with two empty reorder sections
12588e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(true);
12688e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        canvas.insertReorderBarrier(false);
12788e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev        drawOrderedRect(&canvas, 12);
1282f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    });
1292f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev
1302f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
1312f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    ZReorderCanvas canvas(100, 100);
1322f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    RenderNodeDrawable drawable(parent.get(), &canvas, false);
1332f06e8ad1a1c4d0866bb66854d2759e275898635Stan Iliev    canvas.drawDrawable(&drawable);
13488e0891f6657573a5ad918c2d76d6c02bb8ceba3Stan Iliev    EXPECT_EQ(13, canvas.getIndex());
135021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
136021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
137021693b967a2c5556dddd183eb0247df4079e1adStan IlievTEST(RenderNodeDrawable, composeOnLayer)
138021693b967a2c5556dddd183eb0247df4079e1adStan Iliev{
139021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    auto surface = SkSurface::MakeRasterN32Premul(1, 1);
140021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkCanvas& canvas = *surface->getCanvas();
141021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
142021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
143021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
144500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    auto rootNode = TestUtils::createSkiaNode(0, 0, 1, 1,
145021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
146021693b967a2c5556dddd183eb0247df4079e1adStan Iliev            recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
147021693b967a2c5556dddd183eb0247df4079e1adStan Iliev        });
148021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
149021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    //attach a layer to the render node
150021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
151021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    auto canvas2 = surfaceLayer->getCanvas();
152021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
153500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    rootNode->setLayerSurface(surfaceLayer);
154021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
155021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    RenderNodeDrawable drawable1(rootNode.get(), &canvas, false);
156021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas.drawDrawable(&drawable1);
157021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
158021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
159021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    RenderNodeDrawable drawable2(rootNode.get(), &canvas, true);
160021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas.drawDrawable(&drawable2);
161021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    ASSERT_EQ(SK_ColorWHITE, TestUtils::getColor(surface, 0, 0));
162021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
163021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    RenderNodeDrawable drawable3(rootNode.get(), &canvas, false);
164021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    canvas.drawDrawable(&drawable3);
165021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
166021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
167500a0c30d4dcd012218c3e44a62926a1c34a259fStan Iliev    rootNode->setLayerSurface(sk_sp<SkSurface>());
168021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
169021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
170db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievnamespace {
171db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievclass ContextFactory : public IContextFactory {
172db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievpublic:
173db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
174db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        return new AnimationContext(clock);
175db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }
176db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev};
177db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev} // end anonymous namespace
178021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
179db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
180db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_X = 5;
181db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_Y = 10;
182db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionTestCanvas : public SkCanvas {
183db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
184db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
185db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
18652771272f4f018f4fc6846224bf047497e784af1Stan Iliev            const int index = mDrawCounter++;
187db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkMatrix expectedMatrix;;
188db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            switch (index) {
189db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            case 0:  //this is node "B"
190db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
191db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SK_ColorWHITE, paint.getColor());
192db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                expectedMatrix.reset();
19352771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
194db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                break;
195db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            case 1:  //this is node "P"
196db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
197db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
198db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
19952771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50), TestUtils::getLocalClipBounds(this));
200db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                break;
201db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            case 2:  //this is node "C"
202db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
203db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SK_ColorBLUE, paint.getColor());
204db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
20552771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
206db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                break;
207db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            default:
208db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                ADD_FAILURE();
209db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            }
210db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_EQ(expectedMatrix, getTotalMatrix());
211db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
212021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
21352771272f4f018f4fc6846224bf047497e784af1Stan Iliev        int getIndex() { return mDrawCounter; }
214db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    protected:
21552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        int mDrawCounter = 0;
216db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
217db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
218db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /**
219db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
220db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
221db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * draw, but because it is projected backwards, it's drawn in between B and C.
222db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     *
223db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * The parent is scrolled by SCROLL_X/SCROLL_Y, but this does not affect the background
224db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * (which isn't affected by scroll).
225db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     */
226db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto receiverBackground = TestUtils::createSkiaNode(0, 0, 100, 100,
227db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
228db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectionReceiver(true);
229db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // scroll doesn't apply to background, so undone via translationX/Y
230db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
231db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationX(SCROLL_X);
232db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationY(SCROLL_Y);
233db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
234db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkPaint paint;
235db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        paint.setColor(SK_ColorWHITE);
236db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, 100, 100, paint);
237db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "B");
238db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
239db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto projectingRipple = TestUtils::createSkiaNode(50, 0, 100, 50,
240db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
241db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectBackwards(true);
242db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setClipToBounds(false);
243db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkPaint paint;
244db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        paint.setColor(SK_ColorDKGRAY);
245db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(-10, -10, 60, 60, paint);
246db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "P");
247db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto child = TestUtils::createSkiaNode(0, 50, 100, 100,
248db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
249db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkPaint paint;
250db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        paint.setColor(SK_ColorBLUE);
251db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, 100, 50, paint);
252db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(projectingRipple.get());
253db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "C");
254db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
255db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&receiverBackground, &child](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
256db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // Set a rect outline for the projecting ripple to be masked against.
257db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
258db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
259db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.save(SaveFlags::MatrixClip);
260db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
261db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(receiverBackground.get());
262db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(child.get());
263db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.restore();
264db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "A");
265db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
266db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
267db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, parent.get(), &contextFactory));
268db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
269db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
270db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
271db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.observer = nullptr;
272db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    parent->prepareTree(info);
273db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
274db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //parent(A)             -> (receiverBackground, child)
275db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //child(C)              -> (rect[0, 0, 100, 50], projectingRipple)
276db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //projectingRipple(P)   -> (rect[-10, -10, 60, 60]) -> projects backwards
277db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
278db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
279db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
280db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ProjectionTestCanvas canvas(100, 100);
281db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    RenderNodeDrawable drawable(parent.get(), &canvas, true);
282db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas.drawDrawable(&drawable);
283db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, canvas.getIndex());
284db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
285db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
286db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) {
287db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B and C is a layer.
288db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
289db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
290db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
291db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
292db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
293db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
294db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_X = 5;
295db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_Y = 10;
296db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_WIDTH = 400;
297db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_HEIGHT = 400;
298db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int LAYER_WIDTH = 200;
299db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int LAYER_HEIGHT = 200;
300db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionTestCanvas : public SkCanvas {
301db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
3026acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        ProjectionTestCanvas(int* drawCounter)
3036acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT)
30452771272f4f018f4fc6846224bf047497e784af1Stan Iliev            , mDrawCounter(drawCounter)
3056acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        {}
306db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
307db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                const SkPaint&) override {
3086acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(0, (*mDrawCounter)++); //part of painting the layer
30952771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), TestUtils::getClipBounds(this));
310db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
311db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
3126acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(1, (*mDrawCounter)++);
31352771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
314db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
315db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawOval(const SkRect&, const SkPaint&) override {
3166acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(2, (*mDrawCounter)++);
317db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkMatrix expectedMatrix;
318db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            expectedMatrix.setTranslate(100 - SCROLL_X, 100 - SCROLL_Y);
319db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_EQ(expectedMatrix, getTotalMatrix());
32052771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(-85, -80, 295, 300), TestUtils::getLocalClipBounds(this));
321db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
3226acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        int* mDrawCounter;
323db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
324db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
325db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionLayer : public SkSurface_Base {
326db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
3276acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        ProjectionLayer(int* drawCounter)
328db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
3296acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            , mDrawCounter(drawCounter) {
330db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
331db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {
3326acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(3, (*mDrawCounter)++);
333db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
33452771272f4f018f4fc6846224bf047497e784af1Stan Iliev                   300 - SCROLL_Y), TestUtils::getClipBounds(this->getCanvas()));
335db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
336db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkCanvas* onNewCanvas() override {
3376acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            return new ProjectionTestCanvas(mDrawCounter);
338db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
339db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
340db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            return sk_sp<SkSurface>();
341db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
342db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        sk_sp<SkImage> onNewImageSnapshot(SkBudgeted, SkCopyPixelsMode) override {
343db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            return sk_sp<SkImage>();
344db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
345db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onCopyOnWrite(ContentChangeMode) override {}
3466acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        int* mDrawCounter;
347db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
348db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
349db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
350db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
351db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectionReceiver(true);
352db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // scroll doesn't apply to background, so undone via translationX/Y
353db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
354db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationX(SCROLL_X);
355db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationY(SCROLL_Y);
356db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
357db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
358db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "B"); //B
359db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto projectingRipple = TestUtils::createSkiaNode(0, 0, LAYER_WIDTH, LAYER_HEIGHT,
360db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
361db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectBackwards(true);
362db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setClipToBounds(false);
363db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
364db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "R"); //R
365db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto child = TestUtils::createSkiaNode(100, 100, 300, 300,
366db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
367db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(projectingRipple.get());
368db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
369db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "C"); //C
370db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
371db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&receiverBackground, &child](RenderProperties& properties,
372db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkiaRecordingCanvas& canvas) {
373db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // Set a rect outline for the projecting ripple to be masked against.
374db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
375db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
376db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(receiverBackground.get());
377db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(child.get());
378db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "A"); //A
379db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
380db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //prepareTree is required to find, which receivers have backward projected nodes
381db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
382db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
383db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, parent.get(), &contextFactory));
384db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
385db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
386db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
387db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.observer = nullptr;
388db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    parent->prepareTree(info);
389db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
3906acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    int drawCounter = 0;
391db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //set a layer after prepareTree to avoid layer logic there
392db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
3936acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
394db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->setLayerSurface(surfaceLayer1);
395db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    Matrix4 windowTransform;
396db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    windowTransform.loadTranslate(100, 100, 0);
397db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
398db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
399db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    LayerUpdateQueue layerUpdateQueue;
400db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    layerUpdateQueue.enqueueLayerWithDamage(child.get(),
401db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
402db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    SkiaPipeline::renderLayersImpl(layerUpdateQueue, true);
4036acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    EXPECT_EQ(1, drawCounter);  //assert index 0 is drawn on the layer
404db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
4056acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
4066acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    surfaceLayer1->getCanvas()->drawDrawable(&drawable);
4076acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    EXPECT_EQ(4, drawCounter);
408db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
409db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    // clean up layer pointer, so we can safely destruct RenderNode
410db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->setLayerSurface(nullptr);
411db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
412db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
413db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
414db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B.
415db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
416db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
417db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
418db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
419db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
420db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
421db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_X = 500000;
422db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_Y = 0;
423db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_WIDTH = 400;
424db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_HEIGHT = 400;
425db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionChildScrollTestCanvas : public SkCanvas {
426db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
427db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        ProjectionChildScrollTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
428db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
42952771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(0, mDrawCounter++);
430db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_TRUE(getTotalMatrix().isIdentity());
431db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
432db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawOval(const SkRect&, const SkPaint&) override {
43352771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(1, mDrawCounter++);
43452771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
435db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_TRUE(getTotalMatrix().isIdentity());
436db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
43752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        int mDrawCounter = 0;
438db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
439db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
440db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
441db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
442db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectionReceiver(true);
443db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
444db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "B"); //B
445db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto projectingRipple = TestUtils::createSkiaNode(0, 0, 200, 200,
446db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
447db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // scroll doesn't apply to background, so undone via translationX/Y
448db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
449db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationX(SCROLL_X);
450db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationY(SCROLL_Y);
451db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectBackwards(true);
452db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setClipToBounds(false);
453db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawOval(0, 0, 200, 200, SkPaint());
454db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "R"); //R
455db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto child = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
456db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
457db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // Record time clip will be ignored by projectee
4586e49c9f007c879f05b035c40c0ba543c00f9d0d0Mike Reed        canvas.clipRect(100, 100, 300, 300, kIntersect_SkClipOp);
459db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
460db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
461db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(projectingRipple.get());
462db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "C"); //C
463db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
464db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&receiverBackground, &child](RenderProperties& properties,
465db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkiaRecordingCanvas& canvas) {
466db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(receiverBackground.get());
467db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(child.get());
468db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "A"); //A
469db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
470db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //prepareTree is required to find, which receivers have backward projected nodes
471db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
472db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
473db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, parent.get(), &contextFactory));
474db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
475db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
476db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
477db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.observer = nullptr;
478db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    parent->prepareTree(info);
479db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
4806acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
481db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
482db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas->drawDrawable(&drawable);
48352771272f4f018f4fc6846224bf047497e784af1Stan Iliev    EXPECT_EQ(2, canvas->mDrawCounter);
484db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
485db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
486db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievnamespace {
487db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievstatic int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode)
488db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev{
489db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
490db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
491db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, renderNode.get(), &contextFactory));
492db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
493db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
494db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
495db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.observer = nullptr;
496db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    renderNode->prepareTree(info);
497db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
498db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
499db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderCanvas canvas(100, 100);
500db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
501db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas.drawDrawable(&drawable);
502db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    return canvas.getIndex();
503db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
504db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
505db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
506db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) {
507db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B
508db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
509db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
510db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
511db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
512db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
513db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
514db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
515db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
516db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
517db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
518db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
519db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
520db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
521db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
522db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
523db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
524db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
525db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
526db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, drawNode(renderThread, nodeA));
527db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
528db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
529db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) {
530db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on E
531db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  A
532db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                / | \
533db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /  |  \
534db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C   E
535db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
536db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
537db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
538db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
539db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
540db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
541db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
542db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 2
543db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
544db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
545db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
546db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
547db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 3
548db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
549db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeE
550db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
551db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, drawNode(renderThread, nodeA));
552db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
553db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
554db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) {
555db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected without receiver
556db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
557db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
558db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
559db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
560db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
561db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
562db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
563db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
564db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
565db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
566db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
567db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //not having a projection receiver is an undefined behavior
568db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
569db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
570db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
571db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
572db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
573db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, drawNode(renderThread, nodeA));
574db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
575db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
576db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) {
577db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on C
578db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
579db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
580db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
581db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
582db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
583db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
584db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
585db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
586db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
587db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
588db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
589db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
590db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
591db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
592db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
593db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
594db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
595db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, drawNode(renderThread, nodeA));
596db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
597db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
598db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) {
599db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on R
600db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
601db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
602db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
603db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
604db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
605db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
606db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
607db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
608db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
609db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
610db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
611db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //having a node that is projected on itself is an undefined/unexpected behavior
612db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
613db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
614db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
615db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
616db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
617db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
618db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, drawNode(renderThread, nodeA));
619db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
620db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
621db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev//Note: the outcome for this test is different in HWUI
622db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
623db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
624db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
625db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /|\
626db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              / | \
627db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             B  C  R
628db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
629db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
630db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
631db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
632db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
633db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
634db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
635db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
636db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
637db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectBackwards(true);
638db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setClipToBounds(false);
639db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeR
640db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
641db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, drawNode(renderThread, nodeA));
642db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
643db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
644db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling2) {
645db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
646db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
647db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
648db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G
649db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /|\
650db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              / | \
651db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev             B  C  R
652db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
653db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
654db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
655db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
656db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
657db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
658db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeB
659db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
660db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeC
661db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
662db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
663db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
664db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
665db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeG
666db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
667db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, drawNode(renderThread, nodeA));
668db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
669db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
670db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderGrandparentReceivable) {
671db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B
672db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
673db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
674db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                B
675db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
676db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                C
677db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                |
678db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                R
679db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
680db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
681db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
682db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
683db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
684db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
685db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
686db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setProjectBackwards(true);
687db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setClipToBounds(false);
688db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                } ); //nodeR
689db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeC
690db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
691db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
692db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, drawNode(renderThread, nodeA));
693db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
694db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
695db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivables) {
696db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, R is backward projected
697db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
698db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
699db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
700db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
701db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   R
702db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
703db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
704db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
705db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
706db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
707db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
708db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
709db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
710db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
711db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
712db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
713db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
714db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
715db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
716db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
717db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
718db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, drawNode(renderThread, nodeA));
719db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
720db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
721db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesLikelyScenario) {
722db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, G is backward projected
723db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
724db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
725db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
726db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
727db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   R
728db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
729db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
730db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
731db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
732db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
733db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
734db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
735db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
736db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
737db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
738db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
739db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
740db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
741db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
742db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
743db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
744db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, drawNode(renderThread, nodeA));
745db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
746db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
747db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesDeeper) {
748db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* B and G are receivables, R is backward projected
749db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
750db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
751db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
752db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                 / \
753db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                G   D
754db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    |
755db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    R
756db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
757db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
758db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
759db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
760db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
761db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
762db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
763db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
764db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
765db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeG
766db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 4, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //D
767db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
768db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setProjectBackwards(true);
769db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                    props.setClipToBounds(false);
770db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                } ); //nodeR
771db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeD
772db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
773db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
774db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(5, drawNode(renderThread, nodeA));
775021693b967a2c5556dddd183eb0247df4079e1adStan Iliev}
77652771272f4f018f4fc6846224bf047497e784af1Stan Iliev
77752771272f4f018f4fc6846224bf047497e784af1Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, simple) {
77852771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_WIDTH = 100;
77952771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_HEIGHT = 200;
78052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    class SimpleTestCanvas : public TestCanvasBase {
78152771272f4f018f4fc6846224bf047497e784af1Stan Iliev    public:
78252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
78352771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
78452771272f4f018f4fc6846224bf047497e784af1Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
78552771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(0, mDrawCounter++);
78652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
78752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
78852771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(1, mDrawCounter++);
78952771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
79052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    };
79152771272f4f018f4fc6846224bf047497e784af1Stan Iliev
79252771272f4f018f4fc6846224bf047497e784af1Stan Iliev    auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
79352771272f4f018f4fc6846224bf047497e784af1Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
79452771272f4f018f4fc6846224bf047497e784af1Stan Iliev        sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
79552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
79652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawBitmap(*bitmap, 10, 10, nullptr);
79752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
79852771272f4f018f4fc6846224bf047497e784af1Stan Iliev
79952771272f4f018f4fc6846224bf047497e784af1Stan Iliev    SimpleTestCanvas canvas;
80052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    RenderNodeDrawable drawable(node.get(), &canvas, true);
80152771272f4f018f4fc6846224bf047497e784af1Stan Iliev    canvas.drawDrawable(&drawable);
80252771272f4f018f4fc6846224bf047497e784af1Stan Iliev    EXPECT_EQ(2, canvas.mDrawCounter);
80352771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
80452771272f4f018f4fc6846224bf047497e784af1Stan Iliev
80552771272f4f018f4fc6846224bf047497e784af1Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, colorOp_unbounded) {
80652771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_WIDTH = 200;
80752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_HEIGHT = 200;
80852771272f4f018f4fc6846224bf047497e784af1Stan Iliev    class ColorTestCanvas : public TestCanvasBase {
80952771272f4f018f4fc6846224bf047497e784af1Stan Iliev    public:
81052771272f4f018f4fc6846224bf047497e784af1Stan Iliev        ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
81152771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
81252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        void onDrawPaint(const SkPaint&) {
81352771272f4f018f4fc6846224bf047497e784af1Stan Iliev            switch (mDrawCounter++) {
81452771272f4f018f4fc6846224bf047497e784af1Stan Iliev            case 0:
81552771272f4f018f4fc6846224bf047497e784af1Stan Iliev                // While this mirrors FrameBuilder::colorOp_unbounded, this value is different
81652771272f4f018f4fc6846224bf047497e784af1Stan Iliev                // because there is no root (root is clipped in SkiaPipeline::renderFrame).
81752771272f4f018f4fc6846224bf047497e784af1Stan Iliev                // SkiaPipeline.clipped and clip_replace verify the root clip.
81852771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_TRUE(TestUtils::getClipBounds(this).isEmpty());
81952771272f4f018f4fc6846224bf047497e784af1Stan Iliev                break;
82052771272f4f018f4fc6846224bf047497e784af1Stan Iliev            case 1:
82152771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
82252771272f4f018f4fc6846224bf047497e784af1Stan Iliev                break;
82352771272f4f018f4fc6846224bf047497e784af1Stan Iliev            default:
82452771272f4f018f4fc6846224bf047497e784af1Stan Iliev                ADD_FAILURE();
82552771272f4f018f4fc6846224bf047497e784af1Stan Iliev            }
82652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
82752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    };
82852771272f4f018f4fc6846224bf047497e784af1Stan Iliev
82952771272f4f018f4fc6846224bf047497e784af1Stan Iliev    auto unclippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10,
83052771272f4f018f4fc6846224bf047497e784af1Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
83152771272f4f018f4fc6846224bf047497e784af1Stan Iliev        props.setClipToBounds(false);
83252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
83352771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
83452771272f4f018f4fc6846224bf047497e784af1Stan Iliev
83552771272f4f018f4fc6846224bf047497e784af1Stan Iliev    auto clippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10,
83652771272f4f018f4fc6846224bf047497e784af1Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
83752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
83852771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
83952771272f4f018f4fc6846224bf047497e784af1Stan Iliev
84052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    ColorTestCanvas canvas;
84152771272f4f018f4fc6846224bf047497e784af1Stan Iliev    RenderNodeDrawable drawable(unclippedColorView.get(), &canvas, true);
84252771272f4f018f4fc6846224bf047497e784af1Stan Iliev    canvas.drawDrawable(&drawable);
84352771272f4f018f4fc6846224bf047497e784af1Stan Iliev    EXPECT_EQ(1, canvas.mDrawCounter);
84452771272f4f018f4fc6846224bf047497e784af1Stan Iliev    RenderNodeDrawable drawable2(clippedColorView.get(), &canvas, true);
84552771272f4f018f4fc6846224bf047497e784af1Stan Iliev    canvas.drawDrawable(&drawable2);
84652771272f4f018f4fc6846224bf047497e784af1Stan Iliev    EXPECT_EQ(2, canvas.mDrawCounter);
84752771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
84852771272f4f018f4fc6846224bf047497e784af1Stan Iliev
84952771272f4f018f4fc6846224bf047497e784af1Stan IlievTEST(RenderNodeDrawable, renderNode) {
85052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_WIDTH = 200;
85152771272f4f018f4fc6846224bf047497e784af1Stan Iliev    static const int CANVAS_HEIGHT = 200;
85252771272f4f018f4fc6846224bf047497e784af1Stan Iliev    class RenderNodeTestCanvas : public TestCanvasBase {
85352771272f4f018f4fc6846224bf047497e784af1Stan Iliev    public:
85452771272f4f018f4fc6846224bf047497e784af1Stan Iliev        RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
85552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
85652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
85752771272f4f018f4fc6846224bf047497e784af1Stan Iliev            switch(mDrawCounter++) {
85852771272f4f018f4fc6846224bf047497e784af1Stan Iliev            case 0:
85952771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
86052771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
86152771272f4f018f4fc6846224bf047497e784af1Stan Iliev                break;
86252771272f4f018f4fc6846224bf047497e784af1Stan Iliev            case 1:
86352771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
86452771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SK_ColorWHITE, paint.getColor());
86552771272f4f018f4fc6846224bf047497e784af1Stan Iliev                break;
86652771272f4f018f4fc6846224bf047497e784af1Stan Iliev            default:
86752771272f4f018f4fc6846224bf047497e784af1Stan Iliev                ADD_FAILURE();
86852771272f4f018f4fc6846224bf047497e784af1Stan Iliev            }
86952771272f4f018f4fc6846224bf047497e784af1Stan Iliev        }
87052771272f4f018f4fc6846224bf047497e784af1Stan Iliev    };
87152771272f4f018f4fc6846224bf047497e784af1Stan Iliev
87252771272f4f018f4fc6846224bf047497e784af1Stan Iliev    auto child = TestUtils::createSkiaNode(10, 10, 110, 110,
87352771272f4f018f4fc6846224bf047497e784af1Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
87452771272f4f018f4fc6846224bf047497e784af1Stan Iliev        SkPaint paint;
87552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        paint.setColor(SK_ColorWHITE);
87652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawRect(0, 0, 100, 100, paint);
87752771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
87852771272f4f018f4fc6846224bf047497e784af1Stan Iliev
87952771272f4f018f4fc6846224bf047497e784af1Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
88052771272f4f018f4fc6846224bf047497e784af1Stan Iliev            [&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
88152771272f4f018f4fc6846224bf047497e784af1Stan Iliev        SkPaint paint;
88252771272f4f018f4fc6846224bf047497e784af1Stan Iliev        paint.setColor(SK_ColorDKGRAY);
88352771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
88452771272f4f018f4fc6846224bf047497e784af1Stan Iliev
88552771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.save(SaveFlags::MatrixClip);
88652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.translate(40, 40);
88752771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.drawRenderNode(child.get());
88852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        canvas.restore();
88952771272f4f018f4fc6846224bf047497e784af1Stan Iliev    });
89052771272f4f018f4fc6846224bf047497e784af1Stan Iliev
89152771272f4f018f4fc6846224bf047497e784af1Stan Iliev    RenderNodeTestCanvas canvas;
89252771272f4f018f4fc6846224bf047497e784af1Stan Iliev    RenderNodeDrawable drawable(parent.get(), &canvas, true);
89352771272f4f018f4fc6846224bf047497e784af1Stan Iliev    canvas.drawDrawable(&drawable);
89452771272f4f018f4fc6846224bf047497e784af1Stan Iliev    EXPECT_EQ(2, canvas.mDrawCounter);
89552771272f4f018f4fc6846224bf047497e784af1Stan Iliev}
89652771272f4f018f4fc6846224bf047497e784af1Stan Iliev
897