blob: 8260ae213056e87fa359fce55cf0d1921467ac85 [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#ifdef SK_SURFACE_COPY_ON_WRITE_CRASHES
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500473 void onCopyOnWrite(ContentChangeMode) override {}
Ben Wagner9b875562021-10-28 21:42:35 +0000474#else
475 bool onCopyOnWrite(ContentChangeMode) override { return true; }
476#endif
Mike Reed6acfe162016-11-18 17:21:09 -0500477 int* mDrawCounter;
Leon Scroggins III71195ab2018-02-08 17:14:28 -0500478 void onWritePixels(const SkPixmap&, int x, int y) {}
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500479 };
480
John Reck1bcacfd2017-11-03 10:12:19 -0700481 auto receiverBackground = TestUtils::createSkiaNode(
482 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500483 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700484 properties.setProjectionReceiver(true);
485 // scroll doesn't apply to background, so undone via translationX/Y
486 // NOTE: translationX/Y only! no other transform properties may be set for a proj
487 // receiver!
488 properties.setTranslationX(SCROLL_X);
489 properties.setTranslationY(SCROLL_Y);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500490
Mike Reedc2dbc032019-07-25 12:28:29 -0400491 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700492 },
493 "B"); // B
494 auto projectingRipple = TestUtils::createSkiaNode(
495 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500496 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700497 properties.setProjectBackwards(true);
498 properties.setClipToBounds(false);
Mike Reedc2dbc032019-07-25 12:28:29 -0400499 canvas.drawOval(100, 100, 300, 300, Paint()); // drawn mostly out of layer bounds
John Reck1bcacfd2017-11-03 10:12:19 -0700500 },
501 "R"); // R
502 auto child = TestUtils::createSkiaNode(
503 100, 100, 300, 300,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500504 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700505 canvas.drawRenderNode(projectingRipple.get());
Mike Reedc2dbc032019-07-25 12:28:29 -0400506 canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700507 },
508 "C"); // C
509 auto parent = TestUtils::createSkiaNode(
510 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500511 [&receiverBackground, &child](RenderProperties& properties,
John Reck1bcacfd2017-11-03 10:12:19 -0700512 SkiaRecordingCanvas& canvas) {
513 // Set a rect outline for the projecting ripple to be masked against.
514 properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
515 canvas.translate(-SCROLL_X,
516 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
517 canvas.drawRenderNode(receiverBackground.get());
518 canvas.drawRenderNode(child.get());
519 },
520 "A"); // A
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500521
John Reck1bcacfd2017-11-03 10:12:19 -0700522 // prepareTree is required to find, which receivers have backward projected nodes
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500523 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700524 std::unique_ptr<CanvasContext> canvasContext(
525 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500526 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
527 DamageAccumulator damageAccumulator;
528 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500529 parent->prepareTree(info);
530
Mike Reed6acfe162016-11-18 17:21:09 -0500531 int drawCounter = 0;
John Reck1bcacfd2017-11-03 10:12:19 -0700532 // set a layer after prepareTree to avoid layer logic there
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500533 child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
Mike Reed6acfe162016-11-18 17:21:09 -0500534 sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500535 child->setLayerSurface(surfaceLayer1);
536 Matrix4 windowTransform;
537 windowTransform.loadTranslate(100, 100, 0);
538 child->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
539
540 LayerUpdateQueue layerUpdateQueue;
541 layerUpdateQueue.enqueueLayerWithDamage(child.get(),
John Reck1bcacfd2017-11-03 10:12:19 -0700542 android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
Stan Ilieve9d00122017-09-19 12:07:10 -0400543 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
Peiyong Lin1f6aa122018-09-10 16:28:08 -0700544 pipeline->renderLayersImpl(layerUpdateQueue, true);
John Reck1bcacfd2017-11-03 10:12:19 -0700545 EXPECT_EQ(1, drawCounter); // assert index 0 is drawn on the layer
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500546
Mike Reed6acfe162016-11-18 17:21:09 -0500547 RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
548 surfaceLayer1->getCanvas()->drawDrawable(&drawable);
549 EXPECT_EQ(4, drawCounter);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500550
551 // clean up layer pointer, so we can safely destruct RenderNode
552 child->setLayerSurface(nullptr);
553}
554
555RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
556 /* R is backward projected on B.
557 A
558 / \
559 B C
560 |
561 R
562 */
563 static const int SCROLL_X = 500000;
564 static const int SCROLL_Y = 0;
565 static const int CANVAS_WIDTH = 400;
566 static const int CANVAS_HEIGHT = 400;
567 class ProjectionChildScrollTestCanvas : public SkCanvas {
568 public:
569 ProjectionChildScrollTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
570 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
Stan Iliev52771272016-11-17 09:54:38 -0500571 EXPECT_EQ(0, mDrawCounter++);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500572 EXPECT_TRUE(getTotalMatrix().isIdentity());
573 }
574 void onDrawOval(const SkRect&, const SkPaint&) override {
Stan Iliev52771272016-11-17 09:54:38 -0500575 EXPECT_EQ(1, mDrawCounter++);
576 EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500577 EXPECT_TRUE(getTotalMatrix().isIdentity());
578 }
Stan Iliev52771272016-11-17 09:54:38 -0500579 int mDrawCounter = 0;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500580 };
581
John Reck1bcacfd2017-11-03 10:12:19 -0700582 auto receiverBackground = TestUtils::createSkiaNode(
583 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500584 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700585 properties.setProjectionReceiver(true);
Mike Reedc2dbc032019-07-25 12:28:29 -0400586 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700587 },
588 "B"); // B
589 auto projectingRipple = TestUtils::createSkiaNode(
590 0, 0, 200, 200,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500591 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700592 // scroll doesn't apply to background, so undone via translationX/Y
593 // NOTE: translationX/Y only! no other transform properties may be set for a proj
594 // receiver!
595 properties.setTranslationX(SCROLL_X);
596 properties.setTranslationY(SCROLL_Y);
597 properties.setProjectBackwards(true);
598 properties.setClipToBounds(false);
Mike Reedc2dbc032019-07-25 12:28:29 -0400599 canvas.drawOval(0, 0, 200, 200, Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700600 },
601 "R"); // R
602 auto child = TestUtils::createSkiaNode(
603 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500604 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700605 // Record time clip will be ignored by projectee
606 canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500607
John Reck1bcacfd2017-11-03 10:12:19 -0700608 canvas.translate(-SCROLL_X,
609 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
610 canvas.drawRenderNode(projectingRipple.get());
611 },
612 "C"); // C
613 auto parent =
614 TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
615 [&receiverBackground, &child](RenderProperties& properties,
616 SkiaRecordingCanvas& canvas) {
617 canvas.drawRenderNode(receiverBackground.get());
618 canvas.drawRenderNode(child.get());
619 },
620 "A"); // A
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500621
John Reck1bcacfd2017-11-03 10:12:19 -0700622 // prepareTree is required to find, which receivers have backward projected nodes
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500623 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700624 std::unique_ptr<CanvasContext> canvasContext(
625 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500626 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
627 DamageAccumulator damageAccumulator;
628 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500629 parent->prepareTree(info);
630
Mike Reed6acfe162016-11-18 17:21:09 -0500631 std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500632 RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
633 canvas->drawDrawable(&drawable);
Stan Iliev52771272016-11-17 09:54:38 -0500634 EXPECT_EQ(2, canvas->mDrawCounter);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500635}
636
637namespace {
John Reck1bcacfd2017-11-03 10:12:19 -0700638static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500639 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700640 std::unique_ptr<CanvasContext> canvasContext(
641 CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500642 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
643 DamageAccumulator damageAccumulator;
644 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500645 renderNode->prepareTree(info);
646
John Reck1bcacfd2017-11-03 10:12:19 -0700647 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500648 ZReorderCanvas canvas(100, 100);
649 RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
650 canvas.drawDrawable(&drawable);
651 return canvas.getIndex();
652}
653}
654
655RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) {
656 /* R is backward projected on B
657 A
658 / \
659 B C
660 |
661 R
662 */
John Reck1bcacfd2017-11-03 10:12:19 -0700663 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
664 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500665 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
666 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700667 }); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500668 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
669 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
670 props.setProjectBackwards(true);
671 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700672 }); // nodeR
673 }); // nodeC
674 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500675 EXPECT_EQ(3, drawNode(renderThread, nodeA));
676}
677
678RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) {
679 /* R is backward projected on E
680 A
681 / | \
682 / | \
683 B C E
684 |
685 R
686 */
John Reck1bcacfd2017-11-03 10:12:19 -0700687 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
688 SkiaRecordingCanvas& canvas) {
689 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500690 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700691 drawOrderedNode(&canvas, 3, [](RenderProperties& props,
692 SkiaRecordingCanvas& canvas) { // drawn as 2
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500693 props.setProjectBackwards(true);
694 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700695 }); // nodeR
696 }); // nodeC
697 drawOrderedNode(&canvas, 2,
698 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // drawn as 3
699 props.setProjectionReceiver(true);
700 }); // nodeE
701 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500702 EXPECT_EQ(4, drawNode(renderThread, nodeA));
703}
704
705RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) {
706 /* R is backward projected without receiver
707 A
708 / \
709 B C
710 |
711 R
712 */
John Reck1bcacfd2017-11-03 10:12:19 -0700713 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
714 SkiaRecordingCanvas& canvas) {
715 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500716 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
717 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700718 // not having a projection receiver is an undefined behavior
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500719 props.setProjectBackwards(true);
720 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700721 }); // nodeR
722 }); // nodeC
723 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500724 EXPECT_EQ(2, drawNode(renderThread, nodeA));
725}
726
727RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) {
728 /* R is backward projected on C
729 A
730 / \
731 B C
732 |
733 R
734 */
John Reck1bcacfd2017-11-03 10:12:19 -0700735 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
736 SkiaRecordingCanvas& canvas) {
737 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500738 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
739 props.setProjectionReceiver(true);
740 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
741 props.setProjectBackwards(true);
742 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700743 }); // nodeR
744 }); // nodeC
745 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500746 EXPECT_EQ(3, drawNode(renderThread, nodeA));
747}
748
749RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) {
750 /* R is backward projected on R
751 A
752 / \
753 B C
754 |
755 R
756 */
John Reck1bcacfd2017-11-03 10:12:19 -0700757 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
758 SkiaRecordingCanvas& canvas) {
759 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500760 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
761 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700762 // having a node that is projected on itself is an undefined/unexpected behavior
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500763 props.setProjectionReceiver(true);
764 props.setProjectBackwards(true);
765 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700766 }); // nodeR
767 }); // nodeC
768 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500769 EXPECT_EQ(2, drawNode(renderThread, nodeA));
770}
771
John Reck1bcacfd2017-11-03 10:12:19 -0700772// Note: the outcome for this test is different in HWUI
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500773RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
774 /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
775 A
776 /|\
777 / | \
778 B C R
779 */
John Reck1bcacfd2017-11-03 10:12:19 -0700780 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
781 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500782 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
783 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700784 }); // nodeB
785 drawOrderedNode(&canvas, 1,
786 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500787 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
788 props.setProjectBackwards(true);
789 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700790 }); // nodeR
791 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500792 EXPECT_EQ(2, drawNode(renderThread, nodeA));
793}
794
795RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling2) {
796 /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
797 A
798 |
799 G
800 /|\
801 / | \
802 B C R
803 */
John Reck1bcacfd2017-11-03 10:12:19 -0700804 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
805 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500806 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
807 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
808 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700809 }); // nodeB
810 drawOrderedNode(&canvas, 2,
811 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500812 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
813 props.setProjectBackwards(true);
814 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700815 }); // nodeR
816 }); // nodeG
817 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500818 EXPECT_EQ(3, drawNode(renderThread, nodeA));
819}
820
821RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderGrandparentReceivable) {
822 /* R is backward projected on B
823 A
824 |
825 B
826 |
827 C
828 |
829 R
830 */
John Reck1bcacfd2017-11-03 10:12:19 -0700831 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
832 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500833 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
834 props.setProjectionReceiver(true);
835 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700836 drawOrderedNode(&canvas, 2,
837 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
838 props.setProjectBackwards(true);
839 props.setClipToBounds(false);
840 }); // nodeR
841 }); // nodeC
842 }); // nodeB
843 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500844 EXPECT_EQ(3, drawNode(renderThread, nodeA));
845}
846
847RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivables) {
848 /* B and G are receivables, R is backward projected
849 A
850 / \
851 B C
852 / \
853 G R
854 */
John Reck1bcacfd2017-11-03 10:12:19 -0700855 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
856 SkiaRecordingCanvas& canvas) {
857 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500858 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700859 }); // nodeB
860 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
861 drawOrderedNode(&canvas, 3,
862 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
863 props.setProjectionReceiver(true);
864 }); // nodeG
865 drawOrderedNode(&canvas, 1,
866 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
867 props.setProjectBackwards(true);
868 props.setClipToBounds(false);
869 }); // nodeR
870 }); // nodeC
871 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500872 EXPECT_EQ(4, drawNode(renderThread, nodeA));
873}
874
875RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesLikelyScenario) {
876 /* B and G are receivables, G is backward projected
877 A
878 / \
879 B C
880 / \
881 G R
882 */
John Reck1bcacfd2017-11-03 10:12:19 -0700883 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
884 SkiaRecordingCanvas& canvas) {
885 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500886 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700887 }); // nodeB
888 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
889 drawOrderedNode(&canvas, 1,
890 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
891 props.setProjectionReceiver(true);
892 props.setProjectBackwards(true);
893 props.setClipToBounds(false);
894 }); // nodeG
895 drawOrderedNode(&canvas, 3,
896 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
897 }); // nodeR
898 }); // nodeC
899 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500900 EXPECT_EQ(4, drawNode(renderThread, nodeA));
901}
902
903RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesDeeper) {
904 /* B and G are receivables, R is backward projected
905 A
906 / \
907 B C
908 / \
909 G D
910 |
911 R
912 */
John Reck1bcacfd2017-11-03 10:12:19 -0700913 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
914 SkiaRecordingCanvas& canvas) {
915 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500916 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700917 }); // nodeB
918 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
919 drawOrderedNode(&canvas, 2,
920 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
921 props.setProjectionReceiver(true);
922 }); // nodeG
923 drawOrderedNode(&canvas, 4,
924 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // D
925 drawOrderedNode(&canvas, 3, [](RenderProperties& props,
926 SkiaRecordingCanvas& canvas) { // R
927 props.setProjectBackwards(true);
928 props.setClipToBounds(false);
929 }); // nodeR
930 }); // nodeD
931 }); // nodeC
932 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500933 EXPECT_EQ(5, drawNode(renderThread, nodeA));
Stan Iliev021693b2016-10-17 16:26:15 -0400934}
Stan Iliev52771272016-11-17 09:54:38 -0500935
936RENDERTHREAD_TEST(RenderNodeDrawable, simple) {
937 static const int CANVAS_WIDTH = 100;
938 static const int CANVAS_HEIGHT = 200;
939 class SimpleTestCanvas : public TestCanvasBase {
940 public:
John Reck1bcacfd2017-11-03 10:12:19 -0700941 SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Stan Iliev52771272016-11-17 09:54:38 -0500942 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
943 EXPECT_EQ(0, mDrawCounter++);
944 }
Mike Reed2d1279f2020-12-30 09:57:25 -0500945 void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
946 const SkPaint*) override {
Stan Iliev52771272016-11-17 09:54:38 -0500947 EXPECT_EQ(1, mDrawCounter++);
948 }
949 };
950
951 auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
John Reck1bcacfd2017-11-03 10:12:19 -0700952 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
953 sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
954 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Mike Reedc2dbc032019-07-25 12:28:29 -0400955 Paint());
John Reck1bcacfd2017-11-03 10:12:19 -0700956 canvas.drawBitmap(*bitmap, 10, 10, nullptr);
957 });
Stan Iliev52771272016-11-17 09:54:38 -0500958
959 SimpleTestCanvas canvas;
960 RenderNodeDrawable drawable(node.get(), &canvas, true);
961 canvas.drawDrawable(&drawable);
962 EXPECT_EQ(2, canvas.mDrawCounter);
963}
964
965RENDERTHREAD_TEST(RenderNodeDrawable, colorOp_unbounded) {
966 static const int CANVAS_WIDTH = 200;
967 static const int CANVAS_HEIGHT = 200;
968 class ColorTestCanvas : public TestCanvasBase {
969 public:
John Reck1bcacfd2017-11-03 10:12:19 -0700970 ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Stan Iliev52771272016-11-17 09:54:38 -0500971 void onDrawPaint(const SkPaint&) {
972 switch (mDrawCounter++) {
John Reck1bcacfd2017-11-03 10:12:19 -0700973 case 0:
974 EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
975 TestUtils::getClipBounds(this));
976 break;
977 case 1:
978 EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
979 break;
980 default:
981 ADD_FAILURE();
Stan Iliev52771272016-11-17 09:54:38 -0500982 }
983 }
984 };
985
John Reck1bcacfd2017-11-03 10:12:19 -0700986 auto unclippedColorView = TestUtils::createSkiaNode(
987 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
988 props.setClipToBounds(false);
989 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
990 });
Stan Iliev52771272016-11-17 09:54:38 -0500991
John Reck1bcacfd2017-11-03 10:12:19 -0700992 auto clippedColorView = TestUtils::createSkiaNode(
993 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
994 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
995 });
Stan Iliev52771272016-11-17 09:54:38 -0500996
997 ColorTestCanvas canvas;
998 RenderNodeDrawable drawable(unclippedColorView.get(), &canvas, true);
999 canvas.drawDrawable(&drawable);
1000 EXPECT_EQ(1, canvas.mDrawCounter);
1001 RenderNodeDrawable drawable2(clippedColorView.get(), &canvas, true);
1002 canvas.drawDrawable(&drawable2);
1003 EXPECT_EQ(2, canvas.mDrawCounter);
1004}
1005
1006TEST(RenderNodeDrawable, renderNode) {
1007 static const int CANVAS_WIDTH = 200;
1008 static const int CANVAS_HEIGHT = 200;
1009 class RenderNodeTestCanvas : public TestCanvasBase {
1010 public:
John Reck1bcacfd2017-11-03 10:12:19 -07001011 RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Stan Iliev52771272016-11-17 09:54:38 -05001012 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
John Reck1bcacfd2017-11-03 10:12:19 -07001013 switch (mDrawCounter++) {
1014 case 0:
1015 EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
1016 TestUtils::getClipBounds(this));
1017 EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
1018 break;
1019 case 1:
1020 EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
1021 EXPECT_EQ(SK_ColorWHITE, paint.getColor());
1022 break;
1023 default:
1024 ADD_FAILURE();
Stan Iliev52771272016-11-17 09:54:38 -05001025 }
1026 }
1027 };
1028
John Reck1bcacfd2017-11-03 10:12:19 -07001029 auto child = TestUtils::createSkiaNode(
1030 10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -04001031 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -07001032 paint.setColor(SK_ColorWHITE);
1033 canvas.drawRect(0, 0, 100, 100, paint);
1034 });
Stan Iliev52771272016-11-17 09:54:38 -05001035
John Reck1bcacfd2017-11-03 10:12:19 -07001036 auto parent = TestUtils::createSkiaNode(
1037 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Iliev52771272016-11-17 09:54:38 -05001038 [&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -04001039 Paint paint;
John Reck1bcacfd2017-11-03 10:12:19 -07001040 paint.setColor(SK_ColorDKGRAY);
1041 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
Stan Iliev52771272016-11-17 09:54:38 -05001042
John Reck1bcacfd2017-11-03 10:12:19 -07001043 canvas.save(SaveFlags::MatrixClip);
1044 canvas.translate(40, 40);
1045 canvas.drawRenderNode(child.get());
1046 canvas.restore();
1047 });
Stan Iliev52771272016-11-17 09:54:38 -05001048
1049 RenderNodeTestCanvas canvas;
1050 RenderNodeDrawable drawable(parent.get(), &canvas, true);
1051 canvas.drawDrawable(&drawable);
1052 EXPECT_EQ(2, canvas.mDrawCounter);
1053}
1054
Mike Reed2d1279f2020-12-30 09:57:25 -05001055// Verify that layers are composed with linear filtering.
Stan Iliev7e100e92018-01-22 10:36:33 -05001056RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
1057 static const int CANVAS_WIDTH = 1;
1058 static const int CANVAS_HEIGHT = 1;
1059 static const int LAYER_WIDTH = 1;
1060 static const int LAYER_HEIGHT = 1;
1061 class FrameTestCanvas : public TestCanvasBase {
1062 public:
1063 FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Mike Reed2d1279f2020-12-30 09:57:25 -05001064 void onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
1065 const SkSamplingOptions& sampling, const SkPaint* paint,
1066 SrcRectConstraint constraint) override {
Stan Iliev7e100e92018-01-22 10:36:33 -05001067 mDrawCounter++;
Mike Reed2d1279f2020-12-30 09:57:25 -05001068 EXPECT_FALSE(sampling.useCubic);
1069 EXPECT_EQ(SkFilterMode::kLinear, sampling.filter);
Stan Iliev7e100e92018-01-22 10:36:33 -05001070 }
1071 };
1072
1073 auto layerNode = TestUtils::createSkiaNode(
1074 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
1075 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
Mike Reedc2dbc032019-07-25 12:28:29 -04001076 canvas.drawPaint(Paint());
Stan Iliev7e100e92018-01-22 10:36:33 -05001077 });
1078
1079 layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
1080 layerNode->setLayerSurface(SkSurface::MakeRasterN32Premul(LAYER_WIDTH, LAYER_HEIGHT));
1081
1082 FrameTestCanvas canvas;
1083 RenderNodeDrawable drawable(layerNode.get(), &canvas, true);
1084 canvas.drawDrawable(&drawable);
John Reck283bb462018-12-13 16:40:14 -08001085 EXPECT_EQ(1, canvas.mDrawCounter); // make sure the layer was composed
Stan Iliev7e100e92018-01-22 10:36:33 -05001086
1087 // clean up layer pointer, so we can safely destruct RenderNode
1088 layerNode->setLayerSurface(nullptr);
1089}
1090
Stan Ilievd7410f72017-04-04 15:23:54 -04001091TEST(ReorderBarrierDrawable, testShadowMatrix) {
1092 static const int CANVAS_WIDTH = 100;
1093 static const int CANVAS_HEIGHT = 100;
1094 static const float TRANSLATE_X = 11.0f;
1095 static const float TRANSLATE_Y = 22.0f;
1096 static const float CASTER_X = 40.0f;
1097 static const float CASTER_Y = 40.0f;
1098 static const float CASTER_WIDTH = 20.0f;
1099 static const float CASTER_HEIGHT = 20.0f;
1100
Stan Ilievd7410f72017-04-04 15:23:54 -04001101 class ShadowTestCanvas : public SkCanvas {
1102 public:
1103 ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
Stan Iliev54d70322018-06-14 18:00:10 -04001104 int getDrawCounter() { return mDrawCounter; }
Stan Ilievd7410f72017-04-04 15:23:54 -04001105
1106 virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
Nathaniel Nifong31fee3a2019-07-11 16:27:14 -04001107 // Do not expect this to be called. See RecordingCanvas.cpp DrawDrawable for context.
1108 EXPECT_TRUE(false);
Stan Ilievd7410f72017-04-04 15:23:54 -04001109 }
1110
1111 virtual void didTranslate(SkScalar dx, SkScalar dy) override {
1112 mDrawCounter++;
1113 EXPECT_EQ(dx, TRANSLATE_X);
1114 EXPECT_EQ(dy, TRANSLATE_Y);
1115 }
1116
Mike Reed65257632020-11-25 21:31:08 -05001117 virtual void didSetM44(const SkM44& matrix) override {
Stan Ilievd7410f72017-04-04 15:23:54 -04001118 mDrawCounter++;
Stan Iliev54d70322018-06-14 18:00:10 -04001119 // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
1120 // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
Mike Reed65257632020-11-25 21:31:08 -05001121 EXPECT_TRUE(matrix == SkM44());
Stan Iliev54d70322018-06-14 18:00:10 -04001122 EXPECT_TRUE(getTotalMatrix().isIdentity());
1123 }
1124
Mike Reed65257632020-11-25 21:31:08 -05001125 virtual void didConcat44(const SkM44& matrix) override {
Stan Iliev54d70322018-06-14 18:00:10 -04001126 mDrawCounter++;
1127 if (mFirstDidConcat) {
1128 // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
1129 mFirstDidConcat = false;
Mike Reed65257632020-11-25 21:31:08 -05001130 EXPECT_EQ(SkM44::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
Stan Iliev54d70322018-06-14 18:00:10 -04001131 matrix);
Mike Reedc65b1d52020-11-24 12:14:20 -05001132 EXPECT_EQ(SkMatrix::Translate(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
Stan Iliev54d70322018-06-14 18:00:10 -04001133 getTotalMatrix());
1134 } else {
1135 // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
Mike Reed65257632020-11-25 21:31:08 -05001136 EXPECT_EQ(SkM44::Translate(TRANSLATE_X, TRANSLATE_Y), matrix);
Mike Reedc65b1d52020-11-24 12:14:20 -05001137 EXPECT_EQ(SkMatrix::Translate(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix());
Stan Iliev54d70322018-06-14 18:00:10 -04001138 }
Stan Ilievd7410f72017-04-04 15:23:54 -04001139 }
John Reck1bcacfd2017-11-03 10:12:19 -07001140
Stan Ilievd7410f72017-04-04 15:23:54 -04001141 protected:
1142 int mDrawCounter = 0;
John Reck283bb462018-12-13 16:40:14 -08001143
Stan Iliev54d70322018-06-14 18:00:10 -04001144 private:
1145 bool mFirstDidConcat = true;
Stan Ilievd7410f72017-04-04 15:23:54 -04001146 };
1147
John Reck1bcacfd2017-11-03 10:12:19 -07001148 auto parent = TestUtils::createSkiaNode(
1149 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievd7410f72017-04-04 15:23:54 -04001150 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -07001151 canvas.translate(TRANSLATE_X, TRANSLATE_Y);
Leon Scroggins III0f53e102020-05-05 15:53:29 -04001152 canvas.enableZ(true);
Stan Ilievd7410f72017-04-04 15:23:54 -04001153
John Reck1bcacfd2017-11-03 10:12:19 -07001154 auto node = TestUtils::createSkiaNode(
1155 CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT,
1156 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1157 props.setElevation(42);
1158 props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
1159 props.mutableOutline().setShouldClip(true);
1160 });
1161 canvas.drawRenderNode(node.get());
Leon Scroggins III0f53e102020-05-05 15:53:29 -04001162 canvas.enableZ(false);
John Reck1bcacfd2017-11-03 10:12:19 -07001163 });
Stan Ilievd7410f72017-04-04 15:23:54 -04001164
John Reck1bcacfd2017-11-03 10:12:19 -07001165 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievd7410f72017-04-04 15:23:54 -04001166 ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
1167 RenderNodeDrawable drawable(parent.get(), &canvas, false);
Nathaniel Nifong31fee3a2019-07-11 16:27:14 -04001168 drawable.draw(&canvas);
1169 EXPECT_EQ(5, canvas.getDrawCounter());
Stan Iliev65e678f2018-02-07 14:07:30 -05001170}
1171
1172// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
1173RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
1174 static const int CANVAS_WIDTH = 100;
1175 static const int CANVAS_HEIGHT = 200;
1176 class VectorDrawableTestCanvas : public TestCanvasBase {
1177 public:
1178 VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Mike Reed2d1279f2020-12-30 09:57:25 -05001179 void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst,
1180 const SkSamplingOptions&, const SkPaint* paint,
1181 SrcRectConstraint constraint) override {
Mike Reedf2d08ac2020-03-11 09:19:03 -04001182 const int index = mDrawCounter++;
1183 switch (index) {
1184 case 0:
1185 EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
1186 break;
1187 case 1:
1188 EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
1189 break;
1190 default:
1191 ADD_FAILURE();
1192 }
1193 }
Stan Iliev65e678f2018-02-07 14:07:30 -05001194 };
1195
1196 VectorDrawable::Group* group = new VectorDrawable::Group();
1197 sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
John Reck283bb462018-12-13 16:40:14 -08001198 vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH / 10, CANVAS_HEIGHT / 10);
Stan Iliev65e678f2018-02-07 14:07:30 -05001199
John Reck283bb462018-12-13 16:40:14 -08001200 auto node =
1201 TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
1202 [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1203 vectorDrawable->mutateStagingProperties()->setBounds(
1204 SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
1205 canvas.drawVectorDrawable(vectorDrawable.get());
1206 vectorDrawable->mutateStagingProperties()->setBounds(
1207 SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
1208 canvas.drawVectorDrawable(vectorDrawable.get());
1209 });
Stan Iliev65e678f2018-02-07 14:07:30 -05001210
1211 VectorDrawableTestCanvas canvas;
1212 RenderNodeDrawable drawable(node.get(), &canvas, true);
1213 canvas.drawDrawable(&drawable);
1214 EXPECT_EQ(2, canvas.mDrawCounter);
1215}