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
47ea1fe9b9d6ff9f0a543489979a0a909acc9ea564Derek Sollenberger    SkLiteDL skLiteDL;
48021693b967a2c5556dddd183eb0247df4079e1adStan Iliev    SkLiteRecorder canvas;
49ea1fe9b9d6ff9f0a543489979a0a909acc9ea564Derek Sollenberger    canvas.reset(&skLiteDL, SkIRect::MakeWH(1, 1));
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 {
17168885e38b86405b333e3f8fd4ff0a104889147c4Stan Ilievstatic SkRect getRecorderClipBounds(const SkiaRecordingCanvas& recorder) {
17268885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    SkRect clipBounds;
17368885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    recorder.getClipBounds(&clipBounds);
17468885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    return clipBounds;
17568885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev}
17668885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
17768885e38b86405b333e3f8fd4ff0a104889147c4Stan Ilievstatic SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) {
17868885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    SkMatrix matrix;
17968885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    recorder.getMatrix(&matrix);
18068885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    return matrix;
18168885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev}
18268885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev}
18368885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
18468885e38b86405b333e3f8fd4ff0a104889147c4Stan IlievTEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore)
18568885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev{
18668885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    auto surface = SkSurface::MakeRasterN32Premul(400, 800);
18768885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    SkCanvas& canvas = *surface->getCanvas();
18868885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
18968885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
19068885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
19168885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    auto rootNode = TestUtils::createSkiaNode(0, 0, 400, 800,
19268885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev        [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
19368885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            SkPaint layerPaint;
19468885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
19568885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
19668885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
19768885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            //note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
19868885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer);
19968885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
20068885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
20168885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
20268885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
20368885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
20468885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
20568885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            recorder.translate(300.0f, 400.0f);
20668885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
20768885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
20868885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            recorder.restore();
20968885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
21068885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
21168885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
21268885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            SkPaint paint;
21368885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            paint.setAntiAlias(true);
21468885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            paint.setColor(SK_ColorGREEN);
21568885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev            recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
21668885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev        });
21768885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
21868885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    RenderNodeDrawable drawable(rootNode.get(), &canvas, true);
21968885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    canvas.drawDrawable(&drawable);
22068885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev    ASSERT_EQ(SK_ColorGREEN, TestUtils::getColor(surface, 200, 600));
22168885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev}
22268885e38b86405b333e3f8fd4ff0a104889147c4Stan Iliev
22368885e38b86405b333e3f8fd4ff0a104889147c4Stan Ilievnamespace {
224db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievclass ContextFactory : public IContextFactory {
225db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievpublic:
226db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
227db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        return new AnimationContext(clock);
228db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }
229db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev};
230db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev} // end anonymous namespace
231021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
232db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
233db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_X = 5;
234db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_Y = 10;
235db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionTestCanvas : public SkCanvas {
236db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
237db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
238db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
23952771272f4f018f4fc6846224bf047497e784af1Stan Iliev            const int index = mDrawCounter++;
240db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkMatrix expectedMatrix;;
241db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            switch (index) {
242db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            case 0:  //this is node "B"
243db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
244db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SK_ColorWHITE, paint.getColor());
245db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                expectedMatrix.reset();
24652771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
247db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                break;
248db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            case 1:  //this is node "P"
249db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
250db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
251db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
25252771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50), TestUtils::getLocalClipBounds(this));
253db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                break;
254db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            case 2:  //this is node "C"
255db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
256db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                EXPECT_EQ(SK_ColorBLUE, paint.getColor());
257db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
25852771272f4f018f4fc6846224bf047497e784af1Stan Iliev                EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
259db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                break;
260db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            default:
261db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                ADD_FAILURE();
262db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            }
263db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_EQ(expectedMatrix, getTotalMatrix());
264db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
265021693b967a2c5556dddd183eb0247df4079e1adStan Iliev
26652771272f4f018f4fc6846224bf047497e784af1Stan Iliev        int getIndex() { return mDrawCounter; }
267db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    protected:
26852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        int mDrawCounter = 0;
269db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
270db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
271db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /**
272db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
273db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * with a projecting child (P) of its own. P would normally draw between B and C's "background"
274db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * draw, but because it is projected backwards, it's drawn in between B and C.
275db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     *
276db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * The parent is scrolled by SCROLL_X/SCROLL_Y, but this does not affect the background
277db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     * (which isn't affected by scroll).
278db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     */
279db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto receiverBackground = TestUtils::createSkiaNode(0, 0, 100, 100,
280db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
281db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectionReceiver(true);
282db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // scroll doesn't apply to background, so undone via translationX/Y
283db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
284db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationX(SCROLL_X);
285db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationY(SCROLL_Y);
286db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
287db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkPaint paint;
288db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        paint.setColor(SK_ColorWHITE);
289db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, 100, 100, paint);
290db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "B");
291db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
292db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto projectingRipple = TestUtils::createSkiaNode(50, 0, 100, 50,
293db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
294db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectBackwards(true);
295db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setClipToBounds(false);
296db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkPaint paint;
297db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        paint.setColor(SK_ColorDKGRAY);
298db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(-10, -10, 60, 60, paint);
299db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "P");
300db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto child = TestUtils::createSkiaNode(0, 50, 100, 100,
301db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
302db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkPaint paint;
303db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        paint.setColor(SK_ColorBLUE);
304db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, 100, 50, paint);
305db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(projectingRipple.get());
306db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "C");
307db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
308db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&receiverBackground, &child](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
309db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // Set a rect outline for the projecting ripple to be masked against.
310db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
311db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
312db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.save(SaveFlags::MatrixClip);
313db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
314db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(receiverBackground.get());
315db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(child.get());
316db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.restore();
317db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "A");
318db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
319db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
320db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, parent.get(), &contextFactory));
321db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
322db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
323db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
324db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    parent->prepareTree(info);
325db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
326db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //parent(A)             -> (receiverBackground, child)
327db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //child(C)              -> (rect[0, 0, 100, 50], projectingRipple)
328db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //projectingRipple(P)   -> (rect[-10, -10, 60, 60]) -> projects backwards
329db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
330db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
331db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
332db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ProjectionTestCanvas canvas(100, 100);
333db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    RenderNodeDrawable drawable(parent.get(), &canvas, true);
334db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas.drawDrawable(&drawable);
335db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, canvas.getIndex());
336db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
337db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
338db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionHwLayer) {
339db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B and C is a layer.
340db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
341db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
342db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
343db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
344db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
345db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
346db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_X = 5;
347db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_Y = 10;
348db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_WIDTH = 400;
349db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_HEIGHT = 400;
350db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int LAYER_WIDTH = 200;
351db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int LAYER_HEIGHT = 200;
352db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionTestCanvas : public SkCanvas {
353db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
3546acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        ProjectionTestCanvas(int* drawCounter)
3556acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT)
35652771272f4f018f4fc6846224bf047497e784af1Stan Iliev            , mDrawCounter(drawCounter)
3576acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        {}
358db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
359db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                const SkPaint&) override {
3606acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(0, (*mDrawCounter)++); //part of painting the layer
36152771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), TestUtils::getClipBounds(this));
362db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
363db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
3646acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(1, (*mDrawCounter)++);
36552771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
366db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
367db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawOval(const SkRect&, const SkPaint&) override {
3686acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(2, (*mDrawCounter)++);
369db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkMatrix expectedMatrix;
370db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            expectedMatrix.setTranslate(100 - SCROLL_X, 100 - SCROLL_Y);
371db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_EQ(expectedMatrix, getTotalMatrix());
37252771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(-85, -80, 295, 300), TestUtils::getLocalClipBounds(this));
373db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
3746acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        int* mDrawCounter;
375db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
376db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
377db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionLayer : public SkSurface_Base {
378db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
3796acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        ProjectionLayer(int* drawCounter)
380db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
3816acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            , mDrawCounter(drawCounter) {
382db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
383db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {
3846acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            EXPECT_EQ(3, (*mDrawCounter)++);
385db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
38652771272f4f018f4fc6846224bf047497e784af1Stan Iliev                   300 - SCROLL_Y), TestUtils::getClipBounds(this->getCanvas()));
387db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
388db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        SkCanvas* onNewCanvas() override {
3896acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed            return new ProjectionTestCanvas(mDrawCounter);
390db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
391db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
3923c01a07fff19c5166274de5960935875ea89e455Robert Phillips            return nullptr;
393db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
3943c01a07fff19c5166274de5960935875ea89e455Robert Phillips        sk_sp<SkImage> onNewImageSnapshot() override {
3953c01a07fff19c5166274de5960935875ea89e455Robert Phillips            return nullptr;
396db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
397db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onCopyOnWrite(ContentChangeMode) override {}
3986acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed        int* mDrawCounter;
399db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
400db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
401db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
402db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
403db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectionReceiver(true);
404db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // scroll doesn't apply to background, so undone via translationX/Y
405db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
406db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationX(SCROLL_X);
407db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationY(SCROLL_Y);
408db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
409db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
410db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "B"); //B
411db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto projectingRipple = TestUtils::createSkiaNode(0, 0, LAYER_WIDTH, LAYER_HEIGHT,
412db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
413db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectBackwards(true);
414db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setClipToBounds(false);
415db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
416db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "R"); //R
417db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto child = TestUtils::createSkiaNode(100, 100, 300, 300,
418db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
419db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(projectingRipple.get());
420db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
421db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "C"); //C
422db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
423db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&receiverBackground, &child](RenderProperties& properties,
424db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkiaRecordingCanvas& canvas) {
425db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // Set a rect outline for the projecting ripple to be masked against.
426db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
427db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
428db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(receiverBackground.get());
429db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(child.get());
430db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "A"); //A
431db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
432db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //prepareTree is required to find, which receivers have backward projected nodes
433db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
434db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
435db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, parent.get(), &contextFactory));
436db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
437db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
438db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
439db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    parent->prepareTree(info);
440db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
4416acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    int drawCounter = 0;
442db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //set a layer after prepareTree to avoid layer logic there
443db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
4446acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
445db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->setLayerSurface(surfaceLayer1);
446db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    Matrix4 windowTransform;
447db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    windowTransform.loadTranslate(100, 100, 0);
448db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
449db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
450db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    LayerUpdateQueue layerUpdateQueue;
451db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    layerUpdateQueue.enqueueLayerWithDamage(child.get(),
452db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
453db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    SkiaPipeline::renderLayersImpl(layerUpdateQueue, true);
4546acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    EXPECT_EQ(1, drawCounter);  //assert index 0 is drawn on the layer
455db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
4566acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
4576acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    surfaceLayer1->getCanvas()->drawDrawable(&drawable);
4586acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    EXPECT_EQ(4, drawCounter);
459db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
460db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    // clean up layer pointer, so we can safely destruct RenderNode
461db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    child->setLayerSurface(nullptr);
462db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
463db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
464db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
465db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B.
466db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
467db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
468db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
469db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
470db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
471db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
472db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_X = 500000;
473db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int SCROLL_Y = 0;
474db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_WIDTH = 400;
475db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    static const int CANVAS_HEIGHT = 400;
476db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    class ProjectionChildScrollTestCanvas : public SkCanvas {
477db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    public:
478db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        ProjectionChildScrollTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
479db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
48052771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(0, mDrawCounter++);
481db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_TRUE(getTotalMatrix().isIdentity());
482db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
483db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        void onDrawOval(const SkRect&, const SkPaint&) override {
48452771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(1, mDrawCounter++);
48552771272f4f018f4fc6846224bf047497e784af1Stan Iliev            EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
486db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            EXPECT_TRUE(getTotalMatrix().isIdentity());
487db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        }
48852771272f4f018f4fc6846224bf047497e784af1Stan Iliev        int mDrawCounter = 0;
489db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    };
490db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
491db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
492db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
493db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectionReceiver(true);
494db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
495db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "B"); //B
496db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto projectingRipple = TestUtils::createSkiaNode(0, 0, 200, 200,
497db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
498db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // scroll doesn't apply to background, so undone via translationX/Y
499db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
500db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationX(SCROLL_X);
501db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setTranslationY(SCROLL_Y);
502db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setProjectBackwards(true);
503db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        properties.setClipToBounds(false);
504db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawOval(0, 0, 200, 200, SkPaint());
505db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "R"); //R
506db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto child = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
507db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
508db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        // Record time clip will be ignored by projectee
5096c67f1d04591f44bccb476d715a005ad5bbdf840Mike Reed        canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
510db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
511db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
512db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(projectingRipple.get());
513db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "C"); //C
514db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
515db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [&receiverBackground, &child](RenderProperties& properties,
516db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            SkiaRecordingCanvas& canvas) {
517db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(receiverBackground.get());
518db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        canvas.drawRenderNode(child.get());
519db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }, "A"); //A
520db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
521db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //prepareTree is required to find, which receivers have backward projected nodes
522db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
523db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
524db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, parent.get(), &contextFactory));
525db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
526db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
527db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
528db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    parent->prepareTree(info);
529db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
5306acfe16b5650446dbdcce3bd779b52fb6533a41eMike Reed    std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
531db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
532db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas->drawDrawable(&drawable);
53352771272f4f018f4fc6846224bf047497e784af1Stan Iliev    EXPECT_EQ(2, canvas->mDrawCounter);
534db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
535db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
536db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievnamespace {
537db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Ilievstatic int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode)
538db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev{
539db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ContextFactory contextFactory;
540db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
541db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            renderThread, false, renderNode.get(), &contextFactory));
542db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
543db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    DamageAccumulator damageAccumulator;
544db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    info.damageAccumulator = &damageAccumulator;
545db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    renderNode->prepareTree(info);
546db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
547db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
548db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    ZReorderCanvas canvas(100, 100);
549db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
550db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    canvas.drawDrawable(&drawable);
551db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    return canvas.getIndex();
552db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
553db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
554db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
555db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) {
556db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on B
557db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
558db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
559db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
560db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
561db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
562db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
563db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
564db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
565db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
566db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
567db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeB
568db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
569db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
570db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
571db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
572db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
573db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
574db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
575db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, drawNode(renderThread, nodeA));
576db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
577db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
578db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) {
579db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on E
580db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  A
581db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                / | \
582db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               /  |  \
583db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C   E
584db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
585db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
586db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
587db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
588db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
589db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
590db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
591db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 2
592db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
593db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
594db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
595db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
596db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 3
597db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
598db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeE
599db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
600db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(4, drawNode(renderThread, nodeA));
601db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
602db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
603db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) {
604db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected without receiver
605db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
606db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
607db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
608db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
609db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
610db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
611db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
612db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
613db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
614db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
615db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
616db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //not having a projection receiver is an undefined behavior
617db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
618db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
619db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
620db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
621db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
622db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(2, drawNode(renderThread, nodeA));
623db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
624db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
625db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) {
626db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on C
627db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
628db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
629db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
630db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
631db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
632db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
633db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
634db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
635db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
636db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
637db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            props.setProjectionReceiver(true);
638db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
639db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
640db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
641db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            } ); //nodeR
642db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        } ); //nodeC
643db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    }); //nodeA
644db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    EXPECT_EQ(3, drawNode(renderThread, nodeA));
645db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev}
646db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev
647db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan IlievRENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) {
648db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    /* R is backward projected on R
649db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                A
650db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev               / \
651db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev              B   C
652db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  |
653db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                  R
654db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev    */
655db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
656db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
657db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 0, nullptr); //nodeB
658db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev        drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
659db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev            drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
660db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                //having a node that is projected on itself is an undefined/unexpected behavior
661db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectionReceiver(true);
662db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setProjectBackwards(true);
663db45a4bfaff1120a9b23073e46a0cc6d39f56023Stan Iliev                props.setClipToBounds(false);
664