blob: ec949b80ea55e5fb92aec1029edd8e28318fece6 [file] [log] [blame]
Stan Iliev021693b2016-10-17 16:26:15 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Stan Iliev021693b2016-10-17 16:26:15 -040017#include <VectorDrawable.h>
John Reck1bcacfd2017-11-03 10:12:19 -070018#include <gtest/gtest.h>
Stan Iliev021693b2016-10-17 16:26:15 -040019
John Reck1bcacfd2017-11-03 10:12:19 -070020#include <SkClipStack.h>
John Reck1bcacfd2017-11-03 10:12:19 -070021#include <SkSurface_Base.h>
22#include <string.h>
Stan Iliev021693b2016-10-17 16:26:15 -040023#include "AnimationContext.h"
24#include "DamageAccumulator.h"
John Reck1bcacfd2017-11-03 10:12:19 -070025#include "FatalTestCanvas.h"
Stan Iliev021693b2016-10-17 16:26:15 -040026#include "IContextFactory.h"
Mike Reedc2dbc032019-07-25 12:28:29 -040027#include "hwui/Paint.h"
John Reck8f45d4a2018-08-15 10:17:12 -070028#include "RecordingCanvas.h"
John Reck1bcacfd2017-11-03 10:12:19 -070029#include "SkiaCanvas.h"
Stan Iliev021693b2016-10-17 16:26:15 -040030#include "pipeline/skia/SkiaDisplayList.h"
Stan Ilieve9d00122017-09-19 12:07:10 -040031#include "pipeline/skia/SkiaOpenGLPipeline.h"
John Reck1bcacfd2017-11-03 10:12:19 -070032#include "pipeline/skia/SkiaPipeline.h"
Stan Iliev021693b2016-10-17 16:26:15 -040033#include "pipeline/skia/SkiaRecordingCanvas.h"
34#include "renderthread/CanvasContext.h"
35#include "tests/common/TestUtils.h"
Derek Sollenberger72903272018-09-20 14:56:27 -040036#include "utils/Color.h"
Stan Iliev021693b2016-10-17 16:26:15 -040037
38using namespace android;
39using namespace android::uirenderer;
40using namespace android::uirenderer::renderthread;
41using namespace android::uirenderer::skiapipeline;
42
Stan Iliev021693b2016-10-17 16:26:15 -040043TEST(RenderNodeDrawable, create) {
John Reck1bcacfd2017-11-03 10:12:19 -070044 auto rootNode =
45 TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
Stan Iliev021693b2016-10-17 16:26:15 -040046 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
47 });
48
John Reck8f45d4a2018-08-15 10:17:12 -070049 DisplayListData skLiteDL;
50 RecordingCanvas canvas;
Derek Sollenbergerea1fe9b2017-03-01 13:02:43 -050051 canvas.reset(&skLiteDL, SkIRect::MakeWH(1, 1));
Stan Iliev021693b2016-10-17 16:26:15 -040052 canvas.translate(100, 100);
53 RenderNodeDrawable drawable(rootNode.get(), &canvas);
54
55 ASSERT_EQ(drawable.getRenderNode(), rootNode.get());
56 ASSERT_EQ(&drawable.getNodeProperties(), &rootNode->properties());
57 ASSERT_EQ(drawable.getRecordedMatrix(), canvas.getTotalMatrix());
58}
59
Stan Ilievdb45a4b2016-11-08 14:18:31 -050060namespace {
61
Stan Iliev2f06e8a2016-11-02 15:29:03 -040062static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
Mike Reedc2dbc032019-07-25 12:28:29 -040063 Paint paint;
Stan Iliev2f06e8a2016-11-02 15:29:03 -040064 // order put in blue channel, transparent so overlapped content doesn't get rejected
65 paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
66 canvas->drawRect(0, 0, 100, 100, paint);
Stan Iliev021693b2016-10-17 16:26:15 -040067}
68
Stan Iliev2f06e8a2016-11-02 15:29:03 -040069static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
John Reck1bcacfd2017-11-03 10:12:19 -070070 auto node = TestUtils::createSkiaNode(
71 0, 0, 100, 100,
Stan Iliev2f06e8a2016-11-02 15:29:03 -040072 [expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -070073 drawOrderedRect(&canvas, expectedDrawOrder);
74 props.setTranslationZ(z);
75 });
76 canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
Stan Iliev2f06e8a2016-11-02 15:29:03 -040077}
Stan Iliev021693b2016-10-17 16:26:15 -040078
John Reck1bcacfd2017-11-03 10:12:19 -070079static void drawOrderedNode(
80 Canvas* canvas, uint8_t expectedDrawOrder,
Stan Ilievdb45a4b2016-11-08 14:18:31 -050081 std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup) {
John Reck1bcacfd2017-11-03 10:12:19 -070082 auto node = TestUtils::createSkiaNode(
83 0, 0, 100, 100,
Stan Ilievdb45a4b2016-11-08 14:18:31 -050084 [expectedDrawOrder, setup](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -070085 drawOrderedRect(&canvas, expectedDrawOrder);
86 if (setup) {
87 setup(props, canvas);
88 }
89 });
90 canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
Stan Ilievdb45a4b2016-11-08 14:18:31 -050091}
92
93class ZReorderCanvas : public SkCanvas {
94public:
95 ZReorderCanvas(int width, int height) : SkCanvas(width, height) {}
96 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
John Reck1bcacfd2017-11-03 10:12:19 -070097 int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
Stan Iliev52771272016-11-17 09:54:38 -050098 EXPECT_EQ(expectedOrder, mDrawCounter++) << "An op was drawn out of order";
Stan Ilievdb45a4b2016-11-08 14:18:31 -050099 }
Stan Iliev52771272016-11-17 09:54:38 -0500100 int getIndex() { return mDrawCounter; }
John Reck1bcacfd2017-11-03 10:12:19 -0700101
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500102protected:
Stan Iliev52771272016-11-17 09:54:38 -0500103 int mDrawCounter = 0;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500104};
105
John Reck1bcacfd2017-11-03 10:12:19 -0700106} // end anonymous namespace
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500107
108TEST(RenderNodeDrawable, zReorder) {
John Reck1bcacfd2017-11-03 10:12:19 -0700109 auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
110 SkiaRecordingCanvas& canvas) {
Leon Scroggins III0f53e102020-05-05 15:53:29 -0400111 canvas.enableZ(true);
112 canvas.enableZ(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700113 drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400114 drawOrderedRect(&canvas, 1);
Leon Scroggins III0f53e102020-05-05 15:53:29 -0400115 canvas.enableZ(true);
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400116 drawOrderedNode(&canvas, 6, 2.0f);
117 drawOrderedRect(&canvas, 3);
118 drawOrderedNode(&canvas, 4, 0.0f);
119 drawOrderedRect(&canvas, 5);
120 drawOrderedNode(&canvas, 2, -2.0f);
121 drawOrderedNode(&canvas, 7, 2.0f);
Leon Scroggins III0f53e102020-05-05 15:53:29 -0400122 canvas.enableZ(false);
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400123 drawOrderedRect(&canvas, 8);
John Reck1bcacfd2017-11-03 10:12:19 -0700124 drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
Leon Scroggins III0f53e102020-05-05 15:53:29 -0400125 canvas.enableZ(true); // reorder a node ahead of drawrect op
Stan Iliev88e08912016-11-22 18:19:29 -0500126 drawOrderedRect(&canvas, 11);
127 drawOrderedNode(&canvas, 10, -1.0f);
Leon Scroggins III0f53e102020-05-05 15:53:29 -0400128 canvas.enableZ(false);
129 canvas.enableZ(true); // test with two empty reorder sections
130 canvas.enableZ(true);
131 canvas.enableZ(false);
Stan Iliev88e08912016-11-22 18:19:29 -0500132 drawOrderedRect(&canvas, 12);
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400133 });
Stan Iliev021693b2016-10-17 16:26:15 -0400134
John Reck1bcacfd2017-11-03 10:12:19 -0700135 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400136 ZReorderCanvas canvas(100, 100);
137 RenderNodeDrawable drawable(parent.get(), &canvas, false);
138 canvas.drawDrawable(&drawable);
Stan Iliev88e08912016-11-22 18:19:29 -0500139 EXPECT_EQ(13, canvas.getIndex());
Stan Iliev021693b2016-10-17 16:26:15 -0400140}
141
John Reck1bcacfd2017-11-03 10:12:19 -0700142TEST(RenderNodeDrawable, composeOnLayer) {
Stan Iliev021693b2016-10-17 16:26:15 -0400143 auto surface = SkSurface::MakeRasterN32Premul(1, 1);
144 SkCanvas& canvas = *surface->getCanvas();
145 canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
146 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
147
John Reck1bcacfd2017-11-03 10:12:19 -0700148 auto rootNode = TestUtils::createSkiaNode(
149 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
150 recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
151 });
Stan Iliev021693b2016-10-17 16:26:15 -0400152
John Reck1bcacfd2017-11-03 10:12:19 -0700153 // attach a layer to the render node
Stan Iliev021693b2016-10-17 16:26:15 -0400154 auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
155 auto canvas2 = surfaceLayer->getCanvas();
156 canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
Stan Iliev500a0c32016-10-26 10:30:09 -0400157 rootNode->setLayerSurface(surfaceLayer);
Stan Iliev021693b2016-10-17 16:26:15 -0400158
159 RenderNodeDrawable drawable1(rootNode.get(), &canvas, false);
160 canvas.drawDrawable(&drawable1);
161 ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
162
163 RenderNodeDrawable drawable2(rootNode.get(), &canvas, true);
164 canvas.drawDrawable(&drawable2);
165 ASSERT_EQ(SK_ColorWHITE, TestUtils::getColor(surface, 0, 0));
166
167 RenderNodeDrawable drawable3(rootNode.get(), &canvas, false);
168 canvas.drawDrawable(&drawable3);
169 ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
170
Stan Iliev500a0c32016-10-26 10:30:09 -0400171 rootNode->setLayerSurface(sk_sp<SkSurface>());
Stan Iliev021693b2016-10-17 16:26:15 -0400172}
173
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500174namespace {
Stan Iliev68885e32016-12-14 11:18:34 -0500175static SkRect getRecorderClipBounds(const SkiaRecordingCanvas& recorder) {
176 SkRect clipBounds;
177 recorder.getClipBounds(&clipBounds);
178 return clipBounds;
179}
180
181static SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) {
182 SkMatrix matrix;
183 recorder.getMatrix(&matrix);
184 return matrix;
185}
186}
187
John Reck1bcacfd2017-11-03 10:12:19 -0700188TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) {
Stan Iliev68885e32016-12-14 11:18:34 -0500189 auto surface = SkSurface::MakeRasterN32Premul(400, 800);
190 SkCanvas& canvas = *surface->getCanvas();
191 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
192 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
193
John Reck1bcacfd2017-11-03 10:12:19 -0700194 auto rootNode = TestUtils::createSkiaNode(
195 0, 0, 400, 800, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
196 SkPaint layerPaint;
197 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
198 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
Stan Iliev68885e32016-12-14 11:18:34 -0500199
John Reck1bcacfd2017-11-03 10:12:19 -0700200 // note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
John Recka00eef212020-11-16 12:45:55 -0500201 recorder.saveLayer(0, 0, 400, 400, &layerPaint);
John Reck1bcacfd2017-11-03 10:12:19 -0700202 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
203 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
Stan Iliev68885e32016-12-14 11:18:34 -0500204
John Reck1bcacfd2017-11-03 10:12:19 -0700205 recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
206 ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
Stan Iliev68885e32016-12-14 11:18:34 -0500207
John Reck1bcacfd2017-11-03 10:12:19 -0700208 recorder.translate(300.0f, 400.0f);
Mike Reedc65b1d52020-11-24 12:14:20 -0500209 EXPECT_EQ(SkMatrix::Translate(300.0f, 400.0f), getRecorderMatrix(recorder));
Stan Iliev68885e32016-12-14 11:18:34 -0500210
John Reck1bcacfd2017-11-03 10:12:19 -0700211 recorder.restore();
212 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
213 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
Stan Iliev68885e32016-12-14 11:18:34 -0500214
Mike Reedc2dbc032019-07-25 12:28:29 -0400215 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -0700216 paint.setAntiAlias(true);
217 paint.setColor(SK_ColorGREEN);
218 recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
219 });
Stan Iliev68885e32016-12-14 11:18:34 -0500220
221 RenderNodeDrawable drawable(rootNode.get(), &canvas, true);
222 canvas.drawDrawable(&drawable);
223 ASSERT_EQ(SK_ColorGREEN, TestUtils::getColor(surface, 200, 600));
224}
225
226namespace {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500227class ContextFactory : public IContextFactory {
228public:
229 virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
230 return new AnimationContext(clock);
231 }
232};
John Reck1bcacfd2017-11-03 10:12:19 -0700233} // end anonymous namespace
Stan Iliev021693b2016-10-17 16:26:15 -0400234
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500235RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
236 static const int SCROLL_X = 5;
237 static const int SCROLL_Y = 10;
238 class ProjectionTestCanvas : public SkCanvas {
239 public:
240 ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
241 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
Stan Iliev52771272016-11-17 09:54:38 -0500242 const int index = mDrawCounter++;
John Reck1bcacfd2017-11-03 10:12:19 -0700243 SkMatrix expectedMatrix;
244 ;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500245 switch (index) {
John Reck1bcacfd2017-11-03 10:12:19 -0700246 case 0: // this is node "B"
247 EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
248 EXPECT_EQ(SK_ColorWHITE, paint.getColor());
249 expectedMatrix.reset();
250 EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
251 break;
252 case 1: // this is node "P"
253 EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
254 EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
255 expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
256 EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50),
257 TestUtils::getLocalClipBounds(this));
258 break;
259 case 2: // this is node "C"
260 EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
261 EXPECT_EQ(SK_ColorBLUE, paint.getColor());
262 expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
263 EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
264 break;
265 default:
266 ADD_FAILURE();
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500267 }
268 EXPECT_EQ(expectedMatrix, getTotalMatrix());
269 }
Stan Iliev021693b2016-10-17 16:26:15 -0400270
Stan Iliev52771272016-11-17 09:54:38 -0500271 int getIndex() { return mDrawCounter; }
John Reck1bcacfd2017-11-03 10:12:19 -0700272
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500273 protected:
Stan Iliev52771272016-11-17 09:54:38 -0500274 int mDrawCounter = 0;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500275 };
Stan Iliev021693b2016-10-17 16:26:15 -0400276
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500277 /**
278 * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
279 * with a projecting child (P) of its own. P would normally draw between B and C's "background"
280 * draw, but because it is projected backwards, it's drawn in between B and C.
281 *
282 * The parent is scrolled by SCROLL_X/SCROLL_Y, but this does not affect the background
283 * (which isn't affected by scroll).
284 */
John Reck1bcacfd2017-11-03 10:12:19 -0700285 auto receiverBackground = TestUtils::createSkiaNode(
286 0, 0, 100, 100,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500287 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700288 properties.setProjectionReceiver(true);
289 // scroll doesn't apply to background, so undone via translationX/Y
290 // NOTE: translationX/Y only! no other transform properties may be set for a proj
291 // receiver!
292 properties.setTranslationX(SCROLL_X);
293 properties.setTranslationY(SCROLL_Y);
Stan Iliev021693b2016-10-17 16:26:15 -0400294
Mike Reedc2dbc032019-07-25 12:28:29 -0400295 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -0700296 paint.setColor(SK_ColorWHITE);
297 canvas.drawRect(0, 0, 100, 100, paint);
298 },
299 "B");
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500300
John Reck1bcacfd2017-11-03 10:12:19 -0700301 auto projectingRipple = TestUtils::createSkiaNode(
302 50, 0, 100, 50,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500303 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700304 properties.setProjectBackwards(true);
305 properties.setClipToBounds(false);
Mike Reedc2dbc032019-07-25 12:28:29 -0400306 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -0700307 paint.setColor(SK_ColorDKGRAY);
308 canvas.drawRect(-10, -10, 60, 60, paint);
309 },
310 "P");
311 auto child = TestUtils::createSkiaNode(
312 0, 50, 100, 100,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500313 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -0400314 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -0700315 paint.setColor(SK_ColorBLUE);
316 canvas.drawRect(0, 0, 100, 50, paint);
317 canvas.drawRenderNode(projectingRipple.get());
318 },
319 "C");
320 auto parent = TestUtils::createSkiaNode(
321 0, 0, 100, 100,
322 [&receiverBackground, &child](RenderProperties& properties,
323 SkiaRecordingCanvas& canvas) {
324 // Set a rect outline for the projecting ripple to be masked against.
325 properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500326
John Reck1bcacfd2017-11-03 10:12:19 -0700327 canvas.save(SaveFlags::MatrixClip);
328 canvas.translate(-SCROLL_X,
329 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
330 canvas.drawRenderNode(receiverBackground.get());
331 canvas.drawRenderNode(child.get());
332 canvas.restore();
333 },
334 "A");
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500335 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700336 std::unique_ptr<CanvasContext> canvasContext(
337 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500338 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
339 DamageAccumulator damageAccumulator;
340 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500341 parent->prepareTree(info);
342
John Reck1bcacfd2017-11-03 10:12:19 -0700343 // parent(A) -> (receiverBackground, child)
344 // child(C) -> (rect[0, 0, 100, 50], projectingRipple)
345 // projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards
346 // receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500347
John Reck1bcacfd2017-11-03 10:12:19 -0700348 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500349 ProjectionTestCanvas canvas(100, 100);
350 RenderNodeDrawable drawable(parent.get(), &canvas, true);
351 canvas.drawDrawable(&drawable);
352 EXPECT_EQ(3, canvas.getIndex());
353}
354
Yuqian Li70910fd2017-11-29 13:38:40 -0500355RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
356 class ProjectionTestCanvas : public SkCanvas {
357 public:
358 ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
John Reck283bb462018-12-13 16:40:14 -0800359 void onDrawRect(const SkRect& rect, const SkPaint& paint) override { mDrawCounter++; }
Yuqian Li70910fd2017-11-29 13:38:40 -0500360
361 int getDrawCounter() { return mDrawCounter; }
362
363 private:
364 int mDrawCounter = 0;
365 };
366
367 auto receiverBackground = TestUtils::createSkiaNode(
368 0, 0, 100, 100,
369 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
370 properties.setProjectionReceiver(true);
371 },
John Reck283bb462018-12-13 16:40:14 -0800372 "B"); // a receiver with an empty display list
Yuqian Li70910fd2017-11-29 13:38:40 -0500373
374 auto projectingRipple = TestUtils::createSkiaNode(
375 0, 0, 100, 100,
376 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
377 properties.setProjectBackwards(true);
378 properties.setClipToBounds(false);
Mike Reedc2dbc032019-07-25 12:28:29 -0400379 Paint paint;
Yuqian Li70910fd2017-11-29 13:38:40 -0500380 canvas.drawRect(0, 0, 100, 100, paint);
381 },
382 "P");
383 auto child = TestUtils::createSkiaNode(
384 0, 0, 100, 100,
385 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -0400386 Paint paint;
Yuqian Li70910fd2017-11-29 13:38:40 -0500387 canvas.drawRect(0, 0, 100, 100, paint);
388 canvas.drawRenderNode(projectingRipple.get());
389 },
390 "C");
John Reck283bb462018-12-13 16:40:14 -0800391 auto parent =
392 TestUtils::createSkiaNode(0, 0, 100, 100,
393 [&receiverBackground, &child](RenderProperties& properties,
394 SkiaRecordingCanvas& canvas) {
395 canvas.drawRenderNode(receiverBackground.get());
396 canvas.drawRenderNode(child.get());
397 },
398 "A");
Yuqian Li70910fd2017-11-29 13:38:40 -0500399 ContextFactory contextFactory;
400 std::unique_ptr<CanvasContext> canvasContext(
401 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
402 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
403 DamageAccumulator damageAccumulator;
404 info.damageAccumulator = &damageAccumulator;
405 parent->prepareTree(info);
406
407 // parent(A) -> (receiverBackground, child)
408 // child(C) -> (rect[0, 0, 100, 100], projectingRipple)
409 // projectingRipple(P) -> (rect[0, 0, 100, 100]) -> projects backwards
410 // receiverBackground(B) -> (empty) -> projection receiver
411
412 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
413 ProjectionTestCanvas canvas(100, 100);
414 RenderNodeDrawable drawable(parent.get(), &canvas, true);
415 canvas.drawDrawable(&drawable);
416 EXPECT_EQ(2, canvas.getDrawCounter());
417}
418
Stan Ilieve9d00122017-09-19 12:07:10 -0400419RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500420 /* R is backward projected on B and C is a layer.
421 A
422 / \
423 B C
424 |
425 R
426 */
427 static const int SCROLL_X = 5;
428 static const int SCROLL_Y = 10;
429 static const int CANVAS_WIDTH = 400;
430 static const int CANVAS_HEIGHT = 400;
431 static const int LAYER_WIDTH = 200;
432 static const int LAYER_HEIGHT = 200;
433 class ProjectionTestCanvas : public SkCanvas {
434 public:
Mike Reed6acfe162016-11-18 17:21:09 -0500435 ProjectionTestCanvas(int* drawCounter)
John Reck1bcacfd2017-11-03 10:12:19 -0700436 : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT), mDrawCounter(drawCounter) {}
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500437 void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
John Reck1bcacfd2017-11-03 10:12:19 -0700438 const SkPaint&) override {
439 EXPECT_EQ(0, (*mDrawCounter)++); // part of painting the layer
440 EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT),
441 TestUtils::getClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500442 }
443 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
Mike Reed6acfe162016-11-18 17:21:09 -0500444 EXPECT_EQ(1, (*mDrawCounter)++);
John Reck1bcacfd2017-11-03 10:12:19 -0700445 EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT),
446 TestUtils::getClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500447 }
448 void onDrawOval(const SkRect&, const SkPaint&) override {
Mike Reed6acfe162016-11-18 17:21:09 -0500449 EXPECT_EQ(2, (*mDrawCounter)++);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500450 SkMatrix expectedMatrix;
451 expectedMatrix.setTranslate(100 - SCROLL_X, 100 - SCROLL_Y);
452 EXPECT_EQ(expectedMatrix, getTotalMatrix());
Stan Iliev52771272016-11-17 09:54:38 -0500453 EXPECT_EQ(SkRect::MakeLTRB(-85, -80, 295, 300), TestUtils::getLocalClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500454 }
Mike Reed6acfe162016-11-18 17:21:09 -0500455 int* mDrawCounter;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500456 };
457
458 class ProjectionLayer : public SkSurface_Base {
459 public:
Mike Reed6acfe162016-11-18 17:21:09 -0500460 ProjectionLayer(int* drawCounter)
John Reck1bcacfd2017-11-03 10:12:19 -0700461 : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
462 , mDrawCounter(drawCounter) {}
Derek Sollenbergerdbb4bc82018-11-21 08:47:31 -0500463 virtual sk_sp<SkImage> onNewImageSnapshot(const SkIRect* bounds) override {
Mike Reed6acfe162016-11-18 17:21:09 -0500464 EXPECT_EQ(3, (*mDrawCounter)++);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500465 EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
John Reck1bcacfd2017-11-03 10:12:19 -0700466 300 - SCROLL_Y),
467 TestUtils::getClipBounds(this->getCanvas()));
Derek Sollenberger03e6cff72017-12-04 15:07:08 -0500468 return nullptr;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500469 }
John Reck1bcacfd2017-11-03 10:12:19 -0700470 SkCanvas* onNewCanvas() override { return new ProjectionTestCanvas(mDrawCounter); }
471 sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
Ben Wagner9b875562021-10-28 21:42:35 +0000472 bool onCopyOnWrite(ContentChangeMode) override { return true; }
Mike Reed6acfe162016-11-18 17:21:09 -0500473 int* mDrawCounter;
Leon Scroggins III71195ab2018-02-08 17:14:28 -0500474 void onWritePixels(const SkPixmap&, int x, int y) {}
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500475 };
476
John Reck1bcacfd2017-11-03 10:12:19 -0700477 auto receiverBackground = TestUtils::createSkiaNode(
478 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500479 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700480 properties.setProjectionReceiver(true);
481 // scroll doesn't apply to background, so undone via translationX/Y
482 // NOTE: translationX/Y only! no other transform properties may be set for a proj
483 // receiver!
484 properties.setTranslationX(SCROLL_X);
485 properties.setTranslationY(SCROLL_Y);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500486
Mike Reedc2dbc032019-07-25 12:28:29 -0400487 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700488 },
489 "B"); // B
490 auto projectingRipple = TestUtils::createSkiaNode(
491 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500492 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700493 properties.setProjectBackwards(true);
494 properties.setClipToBounds(false);
Mike Reedc2dbc032019-07-25 12:28:29 -0400495 canvas.drawOval(100, 100, 300, 300, Paint()); // drawn mostly out of layer bounds
John Reck1bcacfd2017-11-03 10:12:19 -0700496 },
497 "R"); // R
498 auto child = TestUtils::createSkiaNode(
499 100, 100, 300, 300,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500500 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700501 canvas.drawRenderNode(projectingRipple.get());
Mike Reedc2dbc032019-07-25 12:28:29 -0400502 canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700503 },
504 "C"); // C
505 auto parent = TestUtils::createSkiaNode(
506 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500507 [&receiverBackground, &child](RenderProperties& properties,
John Reck1bcacfd2017-11-03 10:12:19 -0700508 SkiaRecordingCanvas& canvas) {
509 // Set a rect outline for the projecting ripple to be masked against.
510 properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
511 canvas.translate(-SCROLL_X,
512 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
513 canvas.drawRenderNode(receiverBackground.get());
514 canvas.drawRenderNode(child.get());
515 },
516 "A"); // A
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500517
John Reck1bcacfd2017-11-03 10:12:19 -0700518 // prepareTree is required to find, which receivers have backward projected nodes
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500519 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700520 std::unique_ptr<CanvasContext> canvasContext(
521 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500522 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
523 DamageAccumulator damageAccumulator;
524 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500525 parent->prepareTree(info);
526
Mike Reed6acfe162016-11-18 17:21:09 -0500527 int drawCounter = 0;
John Reck1bcacfd2017-11-03 10:12:19 -0700528 // set a layer after prepareTree to avoid layer logic there
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500529 child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
Mike Reed6acfe162016-11-18 17:21:09 -0500530 sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500531 child->setLayerSurface(surfaceLayer1);
532 Matrix4 windowTransform;
533 windowTransform.loadTranslate(100, 100, 0);
534 child->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
535
536 LayerUpdateQueue layerUpdateQueue;
537 layerUpdateQueue.enqueueLayerWithDamage(child.get(),
John Reck1bcacfd2017-11-03 10:12:19 -0700538 android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
Stan Ilieve9d00122017-09-19 12:07:10 -0400539 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
Peiyong Lin1f6aa122018-09-10 16:28:08 -0700540 pipeline->renderLayersImpl(layerUpdateQueue, true);
John Reck1bcacfd2017-11-03 10:12:19 -0700541 EXPECT_EQ(1, drawCounter); // assert index 0 is drawn on the layer
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500542
Mike Reed6acfe162016-11-18 17:21:09 -0500543 RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
544 surfaceLayer1->getCanvas()->drawDrawable(&drawable);
545 EXPECT_EQ(4, drawCounter);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500546
547 // clean up layer pointer, so we can safely destruct RenderNode
548 child->setLayerSurface(nullptr);
549}
550
551RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
552 /* R is backward projected on B.
553 A
554 / \
555 B C
556 |
557 R
558 */
559 static const int SCROLL_X = 500000;
560 static const int SCROLL_Y = 0;
561 static const int CANVAS_WIDTH = 400;
562 static const int CANVAS_HEIGHT = 400;
563 class ProjectionChildScrollTestCanvas : public SkCanvas {
564 public:
565 ProjectionChildScrollTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
566 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
Stan Iliev52771272016-11-17 09:54:38 -0500567 EXPECT_EQ(0, mDrawCounter++);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500568 EXPECT_TRUE(getTotalMatrix().isIdentity());
569 }
570 void onDrawOval(const SkRect&, const SkPaint&) override {
Stan Iliev52771272016-11-17 09:54:38 -0500571 EXPECT_EQ(1, mDrawCounter++);
572 EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500573 EXPECT_TRUE(getTotalMatrix().isIdentity());
574 }
Stan Iliev52771272016-11-17 09:54:38 -0500575 int mDrawCounter = 0;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500576 };
577
John Reck1bcacfd2017-11-03 10:12:19 -0700578 auto receiverBackground = TestUtils::createSkiaNode(
579 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500580 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700581 properties.setProjectionReceiver(true);
Mike Reedc2dbc032019-07-25 12:28:29 -0400582 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700583 },
584 "B"); // B
585 auto projectingRipple = TestUtils::createSkiaNode(
586 0, 0, 200, 200,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500587 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700588 // scroll doesn't apply to background, so undone via translationX/Y
589 // NOTE: translationX/Y only! no other transform properties may be set for a proj
590 // receiver!
591 properties.setTranslationX(SCROLL_X);
592 properties.setTranslationY(SCROLL_Y);
593 properties.setProjectBackwards(true);
594 properties.setClipToBounds(false);
Mike Reedc2dbc032019-07-25 12:28:29 -0400595 canvas.drawOval(0, 0, 200, 200, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700596 },
597 "R"); // R
598 auto child = TestUtils::createSkiaNode(
599 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500600 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700601 // Record time clip will be ignored by projectee
602 canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500603
John Reck1bcacfd2017-11-03 10:12:19 -0700604 canvas.translate(-SCROLL_X,
605 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
606 canvas.drawRenderNode(projectingRipple.get());
607 },
608 "C"); // C
609 auto parent =
610 TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
611 [&receiverBackground, &child](RenderProperties& properties,
612 SkiaRecordingCanvas& canvas) {
613 canvas.drawRenderNode(receiverBackground.get());
614 canvas.drawRenderNode(child.get());
615 },
616 "A"); // A
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500617
John Reck1bcacfd2017-11-03 10:12:19 -0700618 // prepareTree is required to find, which receivers have backward projected nodes
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500619 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700620 std::unique_ptr<CanvasContext> canvasContext(
621 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500622 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
623 DamageAccumulator damageAccumulator;
624 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500625 parent->prepareTree(info);
626
Mike Reed6acfe162016-11-18 17:21:09 -0500627 std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500628 RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
629 canvas->drawDrawable(&drawable);
Stan Iliev52771272016-11-17 09:54:38 -0500630 EXPECT_EQ(2, canvas->mDrawCounter);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500631}
632
633namespace {
John Reck1bcacfd2017-11-03 10:12:19 -0700634static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500635 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700636 std::unique_ptr<CanvasContext> canvasContext(
637 CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500638 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
639 DamageAccumulator damageAccumulator;
640 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500641 renderNode->prepareTree(info);
642
John Reck1bcacfd2017-11-03 10:12:19 -0700643 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500644 ZReorderCanvas canvas(100, 100);
645 RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
646 canvas.drawDrawable(&drawable);
647 return canvas.getIndex();
648}
649}
650
651RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) {
652 /* R is backward projected on B
653 A
654 / \
655 B C
656 |
657 R
658 */
John Reck1bcacfd2017-11-03 10:12:19 -0700659 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
660 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500661 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
662 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700663 }); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500664 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
665 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
666 props.setProjectBackwards(true);
667 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700668 }); // nodeR
669 }); // nodeC
670 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500671 EXPECT_EQ(3, drawNode(renderThread, nodeA));
672}
673
674RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) {
675 /* R is backward projected on E
676 A
677 / | \
678 / | \
679 B C E
680 |
681 R
682 */
John Reck1bcacfd2017-11-03 10:12:19 -0700683 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
684 SkiaRecordingCanvas& canvas) {
685 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500686 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700687 drawOrderedNode(&canvas, 3, [](RenderProperties& props,
688 SkiaRecordingCanvas& canvas) { // drawn as 2
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500689 props.setProjectBackwards(true);
690 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700691 }); // nodeR
692 }); // nodeC
693 drawOrderedNode(&canvas, 2,
694 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // drawn as 3
695 props.setProjectionReceiver(true);
696 }); // nodeE
697 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500698 EXPECT_EQ(4, drawNode(renderThread, nodeA));
699}
700
701RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) {
702 /* R is backward projected without receiver
703 A
704 / \
705 B C
706 |
707 R
708 */
John Reck1bcacfd2017-11-03 10:12:19 -0700709 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
710 SkiaRecordingCanvas& canvas) {
711 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500712 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
713 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700714 // not having a projection receiver is an undefined behavior
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500715 props.setProjectBackwards(true);
716 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700717 }); // nodeR
718 }); // nodeC
719 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500720 EXPECT_EQ(2, drawNode(renderThread, nodeA));
721}
722
723RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) {
724 /* R is backward projected on C
725 A
726 / \
727 B C
728 |
729 R
730 */
John Reck1bcacfd2017-11-03 10:12:19 -0700731 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
732 SkiaRecordingCanvas& canvas) {
733 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500734 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
735 props.setProjectionReceiver(true);
736 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
737 props.setProjectBackwards(true);
738 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700739 }); // nodeR
740 }); // nodeC
741 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500742 EXPECT_EQ(3, drawNode(renderThread, nodeA));
743}
744
745RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) {
746 /* R is backward projected on R
747 A
748 / \
749 B C
750 |
751 R
752 */
John Reck1bcacfd2017-11-03 10:12:19 -0700753 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
754 SkiaRecordingCanvas& canvas) {
755 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500756 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
757 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700758 // having a node that is projected on itself is an undefined/unexpected behavior
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500759 props.setProjectionReceiver(true);
760 props.setProjectBackwards(true);
761 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700762 }); // nodeR
763 }); // nodeC
764 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500765 EXPECT_EQ(2, drawNode(renderThread, nodeA));
766}
767
John Reck1bcacfd2017-11-03 10:12:19 -0700768// Note: the outcome for this test is different in HWUI
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500769RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
770 /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
771 A
772 /|\
773 / | \
774 B C R
775 */
John Reck1bcacfd2017-11-03 10:12:19 -0700776 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
777 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500778 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
779 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700780 }); // nodeB
781 drawOrderedNode(&canvas, 1,
782 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500783 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
784 props.setProjectBackwards(true);
785 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700786 }); // nodeR
787 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500788 EXPECT_EQ(2, drawNode(renderThread, nodeA));
789}
790
791RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling2) {
792 /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
793 A
794 |
795 G
796 /|\
797 / | \
798 B C R
799 */
John Reck1bcacfd2017-11-03 10:12:19 -0700800 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
801 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500802 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
803 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
804 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700805 }); // nodeB
806 drawOrderedNode(&canvas, 2,
807 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500808 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
809 props.setProjectBackwards(true);
810 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700811 }); // nodeR
812 }); // nodeG
813 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500814 EXPECT_EQ(3, drawNode(renderThread, nodeA));
815}
816
817RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderGrandparentReceivable) {
818 /* R is backward projected on B
819 A
820 |
821 B
822 |
823 C
824 |
825 R
826 */
John Reck1bcacfd2017-11-03 10:12:19 -0700827 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
828 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500829 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
830 props.setProjectionReceiver(true);
831 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700832 drawOrderedNode(&canvas, 2,
833 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
834 props.setProjectBackwards(true);
835 props.setClipToBounds(false);
836 }); // nodeR
837 }); // nodeC
838 }); // nodeB
839 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500840 EXPECT_EQ(3, drawNode(renderThread, nodeA));
841}
842
843RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivables) {
844 /* B and G are receivables, R is backward projected
845 A
846 / \
847 B C
848 / \
849 G R
850 */
John Reck1bcacfd2017-11-03 10:12:19 -0700851 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
852 SkiaRecordingCanvas& canvas) {
853 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500854 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700855 }); // nodeB
856 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
857 drawOrderedNode(&canvas, 3,
858 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
859 props.setProjectionReceiver(true);
860 }); // nodeG
861 drawOrderedNode(&canvas, 1,
862 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
863 props.setProjectBackwards(true);
864 props.setClipToBounds(false);
865 }); // nodeR
866 }); // nodeC
867 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500868 EXPECT_EQ(4, drawNode(renderThread, nodeA));
869}
870
871RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesLikelyScenario) {
872 /* B and G are receivables, G is backward projected
873 A
874 / \
875 B C
876 / \
877 G R
878 */
John Reck1bcacfd2017-11-03 10:12:19 -0700879 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
880 SkiaRecordingCanvas& canvas) {
881 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500882 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700883 }); // nodeB
884 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
885 drawOrderedNode(&canvas, 1,
886 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
887 props.setProjectionReceiver(true);
888 props.setProjectBackwards(true);
889 props.setClipToBounds(false);
890 }); // nodeG
891 drawOrderedNode(&canvas, 3,
892 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
893 }); // nodeR
894 }); // nodeC
895 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500896 EXPECT_EQ(4, drawNode(renderThread, nodeA));
897}
898
899RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesDeeper) {
900 /* B and G are receivables, R is backward projected
901 A
902 / \
903 B C
904 / \
905 G D
906 |
907 R
908 */
John Reck1bcacfd2017-11-03 10:12:19 -0700909 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
910 SkiaRecordingCanvas& canvas) {
911 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500912 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700913 }); // nodeB
914 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
915 drawOrderedNode(&canvas, 2,
916 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
917 props.setProjectionReceiver(true);
918 }); // nodeG
919 drawOrderedNode(&canvas, 4,
920 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // D
921 drawOrderedNode(&canvas, 3, [](RenderProperties& props,
922 SkiaRecordingCanvas& canvas) { // R
923 props.setProjectBackwards(true);
924 props.setClipToBounds(false);
925 }); // nodeR
926 }); // nodeD
927 }); // nodeC
928 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500929 EXPECT_EQ(5, drawNode(renderThread, nodeA));
Stan Iliev021693b2016-10-17 16:26:15 -0400930}
Stan Iliev52771272016-11-17 09:54:38 -0500931
932RENDERTHREAD_TEST(RenderNodeDrawable, simple) {
933 static const int CANVAS_WIDTH = 100;
934 static const int CANVAS_HEIGHT = 200;
935 class SimpleTestCanvas : public TestCanvasBase {
936 public:
John Reck1bcacfd2017-11-03 10:12:19 -0700937 SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Stan Iliev52771272016-11-17 09:54:38 -0500938 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
939 EXPECT_EQ(0, mDrawCounter++);
940 }
Mike Reed2d1279f2020-12-30 09:57:25 -0500941 void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
942 const SkPaint*) override {
Stan Iliev52771272016-11-17 09:54:38 -0500943 EXPECT_EQ(1, mDrawCounter++);
944 }
945 };
946
947 auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
John Reck1bcacfd2017-11-03 10:12:19 -0700948 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
949 sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
950 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Mike Reedc2dbc032019-07-25 12:28:29 -0400951 Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700952 canvas.drawBitmap(*bitmap, 10, 10, nullptr);
953 });
Stan Iliev52771272016-11-17 09:54:38 -0500954
955 SimpleTestCanvas canvas;
956 RenderNodeDrawable drawable(node.get(), &canvas, true);
957 canvas.drawDrawable(&drawable);
958 EXPECT_EQ(2, canvas.mDrawCounter);
959}
960
961RENDERTHREAD_TEST(RenderNodeDrawable, colorOp_unbounded) {
962 static const int CANVAS_WIDTH = 200;
963 static const int CANVAS_HEIGHT = 200;
964 class ColorTestCanvas : public TestCanvasBase {
965 public:
John Reck1bcacfd2017-11-03 10:12:19 -0700966 ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Stan Iliev52771272016-11-17 09:54:38 -0500967 void onDrawPaint(const SkPaint&) {
968 switch (mDrawCounter++) {
John Reck1bcacfd2017-11-03 10:12:19 -0700969 case 0:
970 EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
971 TestUtils::getClipBounds(this));
972 break;
973 case 1:
974 EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
975 break;
976 default:
977 ADD_FAILURE();
Stan Iliev52771272016-11-17 09:54:38 -0500978 }
979 }
980 };
981
John Reck1bcacfd2017-11-03 10:12:19 -0700982 auto unclippedColorView = TestUtils::createSkiaNode(
983 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
984 props.setClipToBounds(false);
985 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
986 });
Stan Iliev52771272016-11-17 09:54:38 -0500987
John Reck1bcacfd2017-11-03 10:12:19 -0700988 auto clippedColorView = TestUtils::createSkiaNode(
989 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
990 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
991 });
Stan Iliev52771272016-11-17 09:54:38 -0500992
993 ColorTestCanvas canvas;
994 RenderNodeDrawable drawable(unclippedColorView.get(), &canvas, true);
995 canvas.drawDrawable(&drawable);
996 EXPECT_EQ(1, canvas.mDrawCounter);
997 RenderNodeDrawable drawable2(clippedColorView.get(), &canvas, true);
998 canvas.drawDrawable(&drawable2);
999 EXPECT_EQ(2, canvas.mDrawCounter);
1000}
1001
1002TEST(RenderNodeDrawable, renderNode) {
1003 static const int CANVAS_WIDTH = 200;
1004 static const int CANVAS_HEIGHT = 200;
1005 class RenderNodeTestCanvas : public TestCanvasBase {
1006 public:
John Reck1bcacfd2017-11-03 10:12:19 -07001007 RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Stan Iliev52771272016-11-17 09:54:38 -05001008 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
John Reck1bcacfd2017-11-03 10:12:19 -07001009 switch (mDrawCounter++) {
1010 case 0:
1011 EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
1012 TestUtils::getClipBounds(this));
1013 EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
1014 break;
1015 case 1:
1016 EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
1017 EXPECT_EQ(SK_ColorWHITE, paint.getColor());
1018 break;
1019 default:
1020 ADD_FAILURE();
Stan Iliev52771272016-11-17 09:54:38 -05001021 }
1022 }
1023 };
1024
John Reck1bcacfd2017-11-03 10:12:19 -07001025 auto child = TestUtils::createSkiaNode(
1026 10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -04001027 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -07001028 paint.setColor(SK_ColorWHITE);
1029 canvas.drawRect(0, 0, 100, 100, paint);
1030 });
Stan Iliev52771272016-11-17 09:54:38 -05001031
John Reck1bcacfd2017-11-03 10:12:19 -07001032 auto parent = TestUtils::createSkiaNode(
1033 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Iliev52771272016-11-17 09:54:38 -05001034 [&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -04001035 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -07001036 paint.setColor(SK_ColorDKGRAY);
1037 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
Stan Iliev52771272016-11-17 09:54:38 -05001038
John Reck1bcacfd2017-11-03 10:12:19 -07001039 canvas.save(SaveFlags::MatrixClip);
1040 canvas.translate(40, 40);
1041 canvas.drawRenderNode(child.get());
1042 canvas.restore();
1043 });
Stan Iliev52771272016-11-17 09:54:38 -05001044
1045 RenderNodeTestCanvas canvas;
1046 RenderNodeDrawable drawable(parent.get(), &canvas, true);
1047 canvas.drawDrawable(&drawable);
1048 EXPECT_EQ(2, canvas.mDrawCounter);
1049}
1050
Mike Reed2d1279f2020-12-30 09:57:25 -05001051// Verify that layers are composed with linear filtering.
Stan Iliev7e100e92018-01-22 10:36:33 -05001052RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
1053 static const int CANVAS_WIDTH = 1;
1054 static const int CANVAS_HEIGHT = 1;
1055 static const int LAYER_WIDTH = 1;
1056 static const int LAYER_HEIGHT = 1;
1057 class FrameTestCanvas : public TestCanvasBase {
1058 public:
1059 FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Mike Reed2d1279f2020-12-30 09:57:25 -05001060 void onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
1061 const SkSamplingOptions& sampling, const SkPaint* paint,
1062 SrcRectConstraint constraint) override {
Stan Iliev7e100e92018-01-22 10:36:33 -05001063 mDrawCounter++;
Mike Reed2d1279f2020-12-30 09:57:25 -05001064 EXPECT_FALSE(sampling.useCubic);
1065 EXPECT_EQ(SkFilterMode::kLinear, sampling.filter);
Stan Iliev7e100e92018-01-22 10:36:33 -05001066 }
1067 };
1068
1069 auto layerNode = TestUtils::createSkiaNode(
1070 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
1071 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -04001072 canvas.drawPaint(Paint());
Stan Iliev7e100e92018-01-22 10:36:33 -05001073 });
1074
1075 layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
1076 layerNode->setLayerSurface(SkSurface::MakeRasterN32Premul(LAYER_WIDTH, LAYER_HEIGHT));
1077
1078 FrameTestCanvas canvas;
1079 RenderNodeDrawable drawable(layerNode.get(), &canvas, true);
1080 canvas.drawDrawable(&drawable);
John Reck283bb462018-12-13 16:40:14 -08001081 EXPECT_EQ(1, canvas.mDrawCounter); // make sure the layer was composed
Stan Iliev7e100e92018-01-22 10:36:33 -05001082
1083 // clean up layer pointer, so we can safely destruct RenderNode
1084 layerNode->setLayerSurface(nullptr);
1085}
1086
Stan Ilievd7410f72017-04-04 15:23:54 -04001087TEST(ReorderBarrierDrawable, testShadowMatrix) {
1088 static const int CANVAS_WIDTH = 100;
1089 static const int CANVAS_HEIGHT = 100;
1090 static const float TRANSLATE_X = 11.0f;
1091 static const float TRANSLATE_Y = 22.0f;
1092 static const float CASTER_X = 40.0f;
1093 static const float CASTER_Y = 40.0f;
1094 static const float CASTER_WIDTH = 20.0f;
1095 static const float CASTER_HEIGHT = 20.0f;
1096
Stan Ilievd7410f72017-04-04 15:23:54 -04001097 class ShadowTestCanvas : public SkCanvas {
1098 public:
1099 ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
Stan Iliev54d70322018-06-14 18:00:10 -04001100 int getDrawCounter() { return mDrawCounter; }
Stan Ilievd7410f72017-04-04 15:23:54 -04001101
1102 virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
Nathaniel Nifong31fee3a2019-07-11 16:27:14 -04001103 // Do not expect this to be called. See RecordingCanvas.cpp DrawDrawable for context.
1104 EXPECT_TRUE(false);
Stan Ilievd7410f72017-04-04 15:23:54 -04001105 }
1106
1107 virtual void didTranslate(SkScalar dx, SkScalar dy) override {
1108 mDrawCounter++;
1109 EXPECT_EQ(dx, TRANSLATE_X);
1110 EXPECT_EQ(dy, TRANSLATE_Y);
1111 }
1112
Mike Reed65257632020-11-25 21:31:08 -05001113 virtual void didSetM44(const SkM44& matrix) override {
Stan Ilievd7410f72017-04-04 15:23:54 -04001114 mDrawCounter++;
Stan Iliev54d70322018-06-14 18:00:10 -04001115 // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
1116 // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
Mike Reed65257632020-11-25 21:31:08 -05001117 EXPECT_TRUE(matrix == SkM44());
Stan Iliev54d70322018-06-14 18:00:10 -04001118 EXPECT_TRUE(getTotalMatrix().isIdentity());
1119 }
1120
Mike Reed65257632020-11-25 21:31:08 -05001121 virtual void didConcat44(const SkM44& matrix) override {
Stan Iliev54d70322018-06-14 18:00:10 -04001122 mDrawCounter++;
1123 if (mFirstDidConcat) {
1124 // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
1125 mFirstDidConcat = false;
Mike Reed65257632020-11-25 21:31:08 -05001126 EXPECT_EQ(SkM44::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
Stan Iliev54d70322018-06-14 18:00:10 -04001127 matrix);
Mike Reedc65b1d52020-11-24 12:14:20 -05001128 EXPECT_EQ(SkMatrix::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
Stan Iliev54d70322018-06-14 18:00:10 -04001129 getTotalMatrix());
1130 } else {
1131 // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
Mike Reed65257632020-11-25 21:31:08 -05001132 EXPECT_EQ(SkM44::Translate(TRANSLATE_X, TRANSLATE_Y), matrix);
Mike Reedc65b1d52020-11-24 12:14:20 -05001133 EXPECT_EQ(SkMatrix::Translate(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix());
Stan Iliev54d70322018-06-14 18:00:10 -04001134 }
Stan Ilievd7410f72017-04-04 15:23:54 -04001135 }
John Reck1bcacfd2017-11-03 10:12:19 -07001136
Stan Ilievd7410f72017-04-04 15:23:54 -04001137 protected:
1138 int mDrawCounter = 0;
John Reck283bb462018-12-13 16:40:14 -08001139
Stan Iliev54d70322018-06-14 18:00:10 -04001140 private:
1141 bool mFirstDidConcat = true;
Stan Ilievd7410f72017-04-04 15:23:54 -04001142 };
1143
John Reck1bcacfd2017-11-03 10:12:19 -07001144 auto parent = TestUtils::createSkiaNode(
1145 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievd7410f72017-04-04 15:23:54 -04001146 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -07001147 canvas.translate(TRANSLATE_X, TRANSLATE_Y);
Leon Scroggins III0f53e102020-05-05 15:53:29 -04001148 canvas.enableZ(true);
Stan Ilievd7410f72017-04-04 15:23:54 -04001149
John Reck1bcacfd2017-11-03 10:12:19 -07001150 auto node = TestUtils::createSkiaNode(
1151 CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT,
1152 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1153 props.setElevation(42);
1154 props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
1155 props.mutableOutline().setShouldClip(true);
1156 });
1157 canvas.drawRenderNode(node.get());
Leon Scroggins III0f53e102020-05-05 15:53:29 -04001158 canvas.enableZ(false);
John Reck1bcacfd2017-11-03 10:12:19 -07001159 });
Stan Ilievd7410f72017-04-04 15:23:54 -04001160
John Reck1bcacfd2017-11-03 10:12:19 -07001161 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievd7410f72017-04-04 15:23:54 -04001162 ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
1163 RenderNodeDrawable drawable(parent.get(), &canvas, false);
Nathaniel Nifong31fee3a2019-07-11 16:27:14 -04001164 drawable.draw(&canvas);
1165 EXPECT_EQ(5, canvas.getDrawCounter());
Stan Iliev65e678f2018-02-07 14:07:30 -05001166}
1167
1168// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
1169RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
1170 static const int CANVAS_WIDTH = 100;
1171 static const int CANVAS_HEIGHT = 200;
1172 class VectorDrawableTestCanvas : public TestCanvasBase {
1173 public:
1174 VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Mike Reed2d1279f2020-12-30 09:57:25 -05001175 void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst,
1176 const SkSamplingOptions&, const SkPaint* paint,
1177 SrcRectConstraint constraint) override {
Mike Reedf2d08ac2020-03-11 09:19:03 -04001178 const int index = mDrawCounter++;
1179 switch (index) {
1180 case 0:
1181 EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
1182 break;
1183 case 1:
1184 EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
1185 break;
1186 default:
1187 ADD_FAILURE();
1188 }
1189 }
Stan Iliev65e678f2018-02-07 14:07:30 -05001190 };
1191
1192 VectorDrawable::Group* group = new VectorDrawable::Group();
1193 sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
John Reck283bb462018-12-13 16:40:14 -08001194 vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH / 10, CANVAS_HEIGHT / 10);
Stan Iliev65e678f2018-02-07 14:07:30 -05001195
John Reck283bb462018-12-13 16:40:14 -08001196 auto node =
1197 TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
1198 [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1199 vectorDrawable->mutateStagingProperties()->setBounds(
1200 SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
1201 canvas.drawVectorDrawable(vectorDrawable.get());
1202 vectorDrawable->mutateStagingProperties()->setBounds(
1203 SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
1204 canvas.drawVectorDrawable(vectorDrawable.get());
1205 });
Stan Iliev65e678f2018-02-07 14:07:30 -05001206
1207 VectorDrawableTestCanvas canvas;
1208 RenderNodeDrawable drawable(node.get(), &canvas, true);
1209 canvas.drawDrawable(&drawable);
1210 EXPECT_EQ(2, canvas.mDrawCounter);
1211}