blob: 0331581799b7742a23899f2e1302dc5d64f0ace5 [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"
John Reck8f45d4a2018-08-15 10:17:12 -070027#include "RecordingCanvas.h"
John Reck1bcacfd2017-11-03 10:12:19 -070028#include "SkiaCanvas.h"
Stan Iliev021693b2016-10-17 16:26:15 -040029#include "pipeline/skia/SkiaDisplayList.h"
Stan Ilieve9d00122017-09-19 12:07:10 -040030#include "pipeline/skia/SkiaOpenGLPipeline.h"
John Reck1bcacfd2017-11-03 10:12:19 -070031#include "pipeline/skia/SkiaPipeline.h"
Stan Iliev021693b2016-10-17 16:26:15 -040032#include "pipeline/skia/SkiaRecordingCanvas.h"
33#include "renderthread/CanvasContext.h"
34#include "tests/common/TestUtils.h"
Derek Sollenberger72903272018-09-20 14:56:27 -040035#include "utils/Color.h"
Stan Iliev021693b2016-10-17 16:26:15 -040036
37using namespace android;
38using namespace android::uirenderer;
39using namespace android::uirenderer::renderthread;
40using namespace android::uirenderer::skiapipeline;
41
Stan Iliev021693b2016-10-17 16:26:15 -040042TEST(RenderNodeDrawable, create) {
John Reck1bcacfd2017-11-03 10:12:19 -070043 auto rootNode =
44 TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
Stan Iliev021693b2016-10-17 16:26:15 -040045 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
46 });
47
John Reck8f45d4a2018-08-15 10:17:12 -070048 DisplayListData skLiteDL;
49 RecordingCanvas canvas;
Derek Sollenbergerea1fe9b2017-03-01 13:02:43 -050050 canvas.reset(&skLiteDL, SkIRect::MakeWH(1, 1));
Stan Iliev021693b2016-10-17 16:26:15 -040051 canvas.translate(100, 100);
52 RenderNodeDrawable drawable(rootNode.get(), &canvas);
53
54 ASSERT_EQ(drawable.getRenderNode(), rootNode.get());
55 ASSERT_EQ(&drawable.getNodeProperties(), &rootNode->properties());
56 ASSERT_EQ(drawable.getRecordedMatrix(), canvas.getTotalMatrix());
57}
58
Stan Ilievdb45a4b2016-11-08 14:18:31 -050059namespace {
60
Stan Iliev2f06e8a2016-11-02 15:29:03 -040061static void drawOrderedRect(Canvas* canvas, uint8_t expectedDrawOrder) {
62 SkPaint paint;
63 // order put in blue channel, transparent so overlapped content doesn't get rejected
64 paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
65 canvas->drawRect(0, 0, 100, 100, paint);
Stan Iliev021693b2016-10-17 16:26:15 -040066}
67
Stan Iliev2f06e8a2016-11-02 15:29:03 -040068static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
John Reck1bcacfd2017-11-03 10:12:19 -070069 auto node = TestUtils::createSkiaNode(
70 0, 0, 100, 100,
Stan Iliev2f06e8a2016-11-02 15:29:03 -040071 [expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -070072 drawOrderedRect(&canvas, expectedDrawOrder);
73 props.setTranslationZ(z);
74 });
75 canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
Stan Iliev2f06e8a2016-11-02 15:29:03 -040076}
Stan Iliev021693b2016-10-17 16:26:15 -040077
John Reck1bcacfd2017-11-03 10:12:19 -070078static void drawOrderedNode(
79 Canvas* canvas, uint8_t expectedDrawOrder,
Stan Ilievdb45a4b2016-11-08 14:18:31 -050080 std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup) {
John Reck1bcacfd2017-11-03 10:12:19 -070081 auto node = TestUtils::createSkiaNode(
82 0, 0, 100, 100,
Stan Ilievdb45a4b2016-11-08 14:18:31 -050083 [expectedDrawOrder, setup](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -070084 drawOrderedRect(&canvas, expectedDrawOrder);
85 if (setup) {
86 setup(props, canvas);
87 }
88 });
89 canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
Stan Ilievdb45a4b2016-11-08 14:18:31 -050090}
91
92class ZReorderCanvas : public SkCanvas {
93public:
94 ZReorderCanvas(int width, int height) : SkCanvas(width, height) {}
95 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
John Reck1bcacfd2017-11-03 10:12:19 -070096 int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
Stan Iliev52771272016-11-17 09:54:38 -050097 EXPECT_EQ(expectedOrder, mDrawCounter++) << "An op was drawn out of order";
Stan Ilievdb45a4b2016-11-08 14:18:31 -050098 }
Stan Iliev52771272016-11-17 09:54:38 -050099 int getIndex() { return mDrawCounter; }
John Reck1bcacfd2017-11-03 10:12:19 -0700100
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500101protected:
Stan Iliev52771272016-11-17 09:54:38 -0500102 int mDrawCounter = 0;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500103};
104
John Reck1bcacfd2017-11-03 10:12:19 -0700105} // end anonymous namespace
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500106
107TEST(RenderNodeDrawable, zReorder) {
John Reck1bcacfd2017-11-03 10:12:19 -0700108 auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
109 SkiaRecordingCanvas& canvas) {
Stan Iliev347691f2016-12-01 12:25:07 -0500110 canvas.insertReorderBarrier(true);
111 canvas.insertReorderBarrier(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700112 drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400113 drawOrderedRect(&canvas, 1);
114 canvas.insertReorderBarrier(true);
115 drawOrderedNode(&canvas, 6, 2.0f);
116 drawOrderedRect(&canvas, 3);
117 drawOrderedNode(&canvas, 4, 0.0f);
118 drawOrderedRect(&canvas, 5);
119 drawOrderedNode(&canvas, 2, -2.0f);
120 drawOrderedNode(&canvas, 7, 2.0f);
121 canvas.insertReorderBarrier(false);
122 drawOrderedRect(&canvas, 8);
John Reck1bcacfd2017-11-03 10:12:19 -0700123 drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
124 canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op
Stan Iliev88e08912016-11-22 18:19:29 -0500125 drawOrderedRect(&canvas, 11);
126 drawOrderedNode(&canvas, 10, -1.0f);
127 canvas.insertReorderBarrier(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700128 canvas.insertReorderBarrier(true); // test with two empty reorder sections
Stan Iliev88e08912016-11-22 18:19:29 -0500129 canvas.insertReorderBarrier(true);
130 canvas.insertReorderBarrier(false);
131 drawOrderedRect(&canvas, 12);
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400132 });
Stan Iliev021693b2016-10-17 16:26:15 -0400133
John Reck1bcacfd2017-11-03 10:12:19 -0700134 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400135 ZReorderCanvas canvas(100, 100);
136 RenderNodeDrawable drawable(parent.get(), &canvas, false);
137 canvas.drawDrawable(&drawable);
Stan Iliev88e08912016-11-22 18:19:29 -0500138 EXPECT_EQ(13, canvas.getIndex());
Stan Iliev021693b2016-10-17 16:26:15 -0400139}
140
John Reck1bcacfd2017-11-03 10:12:19 -0700141TEST(RenderNodeDrawable, composeOnLayer) {
Stan Iliev021693b2016-10-17 16:26:15 -0400142 auto surface = SkSurface::MakeRasterN32Premul(1, 1);
143 SkCanvas& canvas = *surface->getCanvas();
144 canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
145 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
146
John Reck1bcacfd2017-11-03 10:12:19 -0700147 auto rootNode = TestUtils::createSkiaNode(
148 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
149 recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
150 });
Stan Iliev021693b2016-10-17 16:26:15 -0400151
John Reck1bcacfd2017-11-03 10:12:19 -0700152 // attach a layer to the render node
Stan Iliev021693b2016-10-17 16:26:15 -0400153 auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
154 auto canvas2 = surfaceLayer->getCanvas();
155 canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
Stan Iliev500a0c32016-10-26 10:30:09 -0400156 rootNode->setLayerSurface(surfaceLayer);
Stan Iliev021693b2016-10-17 16:26:15 -0400157
158 RenderNodeDrawable drawable1(rootNode.get(), &canvas, false);
159 canvas.drawDrawable(&drawable1);
160 ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
161
162 RenderNodeDrawable drawable2(rootNode.get(), &canvas, true);
163 canvas.drawDrawable(&drawable2);
164 ASSERT_EQ(SK_ColorWHITE, TestUtils::getColor(surface, 0, 0));
165
166 RenderNodeDrawable drawable3(rootNode.get(), &canvas, false);
167 canvas.drawDrawable(&drawable3);
168 ASSERT_EQ(SK_ColorRED, TestUtils::getColor(surface, 0, 0));
169
Stan Iliev500a0c32016-10-26 10:30:09 -0400170 rootNode->setLayerSurface(sk_sp<SkSurface>());
Stan Iliev021693b2016-10-17 16:26:15 -0400171}
172
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500173namespace {
Stan Iliev68885e32016-12-14 11:18:34 -0500174static SkRect getRecorderClipBounds(const SkiaRecordingCanvas& recorder) {
175 SkRect clipBounds;
176 recorder.getClipBounds(&clipBounds);
177 return clipBounds;
178}
179
180static SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) {
181 SkMatrix matrix;
182 recorder.getMatrix(&matrix);
183 return matrix;
184}
185}
186
John Reck1bcacfd2017-11-03 10:12:19 -0700187TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) {
Stan Iliev68885e32016-12-14 11:18:34 -0500188 auto surface = SkSurface::MakeRasterN32Premul(400, 800);
189 SkCanvas& canvas = *surface->getCanvas();
190 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
191 ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
192
John Reck1bcacfd2017-11-03 10:12:19 -0700193 auto rootNode = TestUtils::createSkiaNode(
194 0, 0, 400, 800, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
195 SkPaint layerPaint;
196 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
197 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
Stan Iliev68885e32016-12-14 11:18:34 -0500198
John Reck1bcacfd2017-11-03 10:12:19 -0700199 // note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
200 recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer);
201 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
202 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
Stan Iliev68885e32016-12-14 11:18:34 -0500203
John Reck1bcacfd2017-11-03 10:12:19 -0700204 recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
205 ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
Stan Iliev68885e32016-12-14 11:18:34 -0500206
John Reck1bcacfd2017-11-03 10:12:19 -0700207 recorder.translate(300.0f, 400.0f);
208 EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
Stan Iliev68885e32016-12-14 11:18:34 -0500209
John Reck1bcacfd2017-11-03 10:12:19 -0700210 recorder.restore();
211 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
212 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
Stan Iliev68885e32016-12-14 11:18:34 -0500213
John Reck1bcacfd2017-11-03 10:12:19 -0700214 SkPaint paint;
215 paint.setAntiAlias(true);
216 paint.setColor(SK_ColorGREEN);
217 recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
218 });
Stan Iliev68885e32016-12-14 11:18:34 -0500219
220 RenderNodeDrawable drawable(rootNode.get(), &canvas, true);
221 canvas.drawDrawable(&drawable);
222 ASSERT_EQ(SK_ColorGREEN, TestUtils::getColor(surface, 200, 600));
223}
224
225namespace {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500226class ContextFactory : public IContextFactory {
227public:
228 virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
229 return new AnimationContext(clock);
230 }
231};
John Reck1bcacfd2017-11-03 10:12:19 -0700232} // end anonymous namespace
Stan Iliev021693b2016-10-17 16:26:15 -0400233
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500234RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
235 static const int SCROLL_X = 5;
236 static const int SCROLL_Y = 10;
237 class ProjectionTestCanvas : public SkCanvas {
238 public:
239 ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
240 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
Stan Iliev52771272016-11-17 09:54:38 -0500241 const int index = mDrawCounter++;
John Reck1bcacfd2017-11-03 10:12:19 -0700242 SkMatrix expectedMatrix;
243 ;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500244 switch (index) {
John Reck1bcacfd2017-11-03 10:12:19 -0700245 case 0: // this is node "B"
246 EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
247 EXPECT_EQ(SK_ColorWHITE, paint.getColor());
248 expectedMatrix.reset();
249 EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
250 break;
251 case 1: // this is node "P"
252 EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
253 EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
254 expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
255 EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50),
256 TestUtils::getLocalClipBounds(this));
257 break;
258 case 2: // this is node "C"
259 EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
260 EXPECT_EQ(SK_ColorBLUE, paint.getColor());
261 expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
262 EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
263 break;
264 default:
265 ADD_FAILURE();
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500266 }
267 EXPECT_EQ(expectedMatrix, getTotalMatrix());
268 }
Stan Iliev021693b2016-10-17 16:26:15 -0400269
Stan Iliev52771272016-11-17 09:54:38 -0500270 int getIndex() { return mDrawCounter; }
John Reck1bcacfd2017-11-03 10:12:19 -0700271
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500272 protected:
Stan Iliev52771272016-11-17 09:54:38 -0500273 int mDrawCounter = 0;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500274 };
Stan Iliev021693b2016-10-17 16:26:15 -0400275
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500276 /**
277 * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
278 * with a projecting child (P) of its own. P would normally draw between B and C's "background"
279 * draw, but because it is projected backwards, it's drawn in between B and C.
280 *
281 * The parent is scrolled by SCROLL_X/SCROLL_Y, but this does not affect the background
282 * (which isn't affected by scroll).
283 */
John Reck1bcacfd2017-11-03 10:12:19 -0700284 auto receiverBackground = TestUtils::createSkiaNode(
285 0, 0, 100, 100,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500286 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700287 properties.setProjectionReceiver(true);
288 // scroll doesn't apply to background, so undone via translationX/Y
289 // NOTE: translationX/Y only! no other transform properties may be set for a proj
290 // receiver!
291 properties.setTranslationX(SCROLL_X);
292 properties.setTranslationY(SCROLL_Y);
Stan Iliev021693b2016-10-17 16:26:15 -0400293
John Reck1bcacfd2017-11-03 10:12:19 -0700294 SkPaint paint;
295 paint.setColor(SK_ColorWHITE);
296 canvas.drawRect(0, 0, 100, 100, paint);
297 },
298 "B");
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500299
John Reck1bcacfd2017-11-03 10:12:19 -0700300 auto projectingRipple = TestUtils::createSkiaNode(
301 50, 0, 100, 50,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500302 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700303 properties.setProjectBackwards(true);
304 properties.setClipToBounds(false);
305 SkPaint paint;
306 paint.setColor(SK_ColorDKGRAY);
307 canvas.drawRect(-10, -10, 60, 60, paint);
308 },
309 "P");
310 auto child = TestUtils::createSkiaNode(
311 0, 50, 100, 100,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500312 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700313 SkPaint paint;
314 paint.setColor(SK_ColorBLUE);
315 canvas.drawRect(0, 0, 100, 50, paint);
316 canvas.drawRenderNode(projectingRipple.get());
317 },
318 "C");
319 auto parent = TestUtils::createSkiaNode(
320 0, 0, 100, 100,
321 [&receiverBackground, &child](RenderProperties& properties,
322 SkiaRecordingCanvas& canvas) {
323 // Set a rect outline for the projecting ripple to be masked against.
324 properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500325
John Reck1bcacfd2017-11-03 10:12:19 -0700326 canvas.save(SaveFlags::MatrixClip);
327 canvas.translate(-SCROLL_X,
328 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
329 canvas.drawRenderNode(receiverBackground.get());
330 canvas.drawRenderNode(child.get());
331 canvas.restore();
332 },
333 "A");
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500334 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700335 std::unique_ptr<CanvasContext> canvasContext(
336 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500337 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
338 DamageAccumulator damageAccumulator;
339 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500340 parent->prepareTree(info);
341
John Reck1bcacfd2017-11-03 10:12:19 -0700342 // parent(A) -> (receiverBackground, child)
343 // child(C) -> (rect[0, 0, 100, 50], projectingRipple)
344 // projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards
345 // receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500346
John Reck1bcacfd2017-11-03 10:12:19 -0700347 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500348 ProjectionTestCanvas canvas(100, 100);
349 RenderNodeDrawable drawable(parent.get(), &canvas, true);
350 canvas.drawDrawable(&drawable);
351 EXPECT_EQ(3, canvas.getIndex());
352}
353
Yuqian Li70910fd2017-11-29 13:38:40 -0500354RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, emptyReceiver) {
355 class ProjectionTestCanvas : public SkCanvas {
356 public:
357 ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
358 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
359 mDrawCounter++;
360 }
361
362 int getDrawCounter() { return mDrawCounter; }
363
364 private:
365 int mDrawCounter = 0;
366 };
367
368 auto receiverBackground = TestUtils::createSkiaNode(
369 0, 0, 100, 100,
370 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
371 properties.setProjectionReceiver(true);
372 },
373 "B"); // a receiver with an empty display list
374
375 auto projectingRipple = TestUtils::createSkiaNode(
376 0, 0, 100, 100,
377 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
378 properties.setProjectBackwards(true);
379 properties.setClipToBounds(false);
380 SkPaint paint;
381 canvas.drawRect(0, 0, 100, 100, paint);
382 },
383 "P");
384 auto child = TestUtils::createSkiaNode(
385 0, 0, 100, 100,
386 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
387 SkPaint paint;
388 canvas.drawRect(0, 0, 100, 100, paint);
389 canvas.drawRenderNode(projectingRipple.get());
390 },
391 "C");
392 auto parent = TestUtils::createSkiaNode(
393 0, 0, 100, 100,
394 [&receiverBackground, &child](RenderProperties& properties,
395 SkiaRecordingCanvas& canvas) {
396 canvas.drawRenderNode(receiverBackground.get());
397 canvas.drawRenderNode(child.get());
398 },
399 "A");
400 ContextFactory contextFactory;
401 std::unique_ptr<CanvasContext> canvasContext(
402 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
403 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
404 DamageAccumulator damageAccumulator;
405 info.damageAccumulator = &damageAccumulator;
406 parent->prepareTree(info);
407
408 // parent(A) -> (receiverBackground, child)
409 // child(C) -> (rect[0, 0, 100, 100], projectingRipple)
410 // projectingRipple(P) -> (rect[0, 0, 100, 100]) -> projects backwards
411 // receiverBackground(B) -> (empty) -> projection receiver
412
413 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
414 ProjectionTestCanvas canvas(100, 100);
415 RenderNodeDrawable drawable(parent.get(), &canvas, true);
416 canvas.drawDrawable(&drawable);
417 EXPECT_EQ(2, canvas.getDrawCounter());
418}
419
Stan Ilieve9d00122017-09-19 12:07:10 -0400420RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500421 /* R is backward projected on B and C is a layer.
422 A
423 / \
424 B C
425 |
426 R
427 */
428 static const int SCROLL_X = 5;
429 static const int SCROLL_Y = 10;
430 static const int CANVAS_WIDTH = 400;
431 static const int CANVAS_HEIGHT = 400;
432 static const int LAYER_WIDTH = 200;
433 static const int LAYER_HEIGHT = 200;
434 class ProjectionTestCanvas : public SkCanvas {
435 public:
Mike Reed6acfe162016-11-18 17:21:09 -0500436 ProjectionTestCanvas(int* drawCounter)
John Reck1bcacfd2017-11-03 10:12:19 -0700437 : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT), mDrawCounter(drawCounter) {}
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500438 void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
John Reck1bcacfd2017-11-03 10:12:19 -0700439 const SkPaint&) override {
440 EXPECT_EQ(0, (*mDrawCounter)++); // part of painting the layer
441 EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT),
442 TestUtils::getClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500443 }
444 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
Mike Reed6acfe162016-11-18 17:21:09 -0500445 EXPECT_EQ(1, (*mDrawCounter)++);
John Reck1bcacfd2017-11-03 10:12:19 -0700446 EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT),
447 TestUtils::getClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500448 }
449 void onDrawOval(const SkRect&, const SkPaint&) override {
Mike Reed6acfe162016-11-18 17:21:09 -0500450 EXPECT_EQ(2, (*mDrawCounter)++);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500451 SkMatrix expectedMatrix;
452 expectedMatrix.setTranslate(100 - SCROLL_X, 100 - SCROLL_Y);
453 EXPECT_EQ(expectedMatrix, getTotalMatrix());
Stan Iliev52771272016-11-17 09:54:38 -0500454 EXPECT_EQ(SkRect::MakeLTRB(-85, -80, 295, 300), TestUtils::getLocalClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500455 }
Mike Reed6acfe162016-11-18 17:21:09 -0500456 int* mDrawCounter;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500457 };
458
459 class ProjectionLayer : public SkSurface_Base {
460 public:
Mike Reed6acfe162016-11-18 17:21:09 -0500461 ProjectionLayer(int* drawCounter)
John Reck1bcacfd2017-11-03 10:12:19 -0700462 : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
463 , mDrawCounter(drawCounter) {}
Derek Sollenbergerdbb4bc82018-11-21 08:47:31 -0500464 virtual sk_sp<SkImage> onNewImageSnapshot(const SkIRect* bounds) override {
Mike Reed6acfe162016-11-18 17:21:09 -0500465 EXPECT_EQ(3, (*mDrawCounter)++);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500466 EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
John Reck1bcacfd2017-11-03 10:12:19 -0700467 300 - SCROLL_Y),
468 TestUtils::getClipBounds(this->getCanvas()));
Derek Sollenberger03e6cff72017-12-04 15:07:08 -0500469 return nullptr;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500470 }
John Reck1bcacfd2017-11-03 10:12:19 -0700471 SkCanvas* onNewCanvas() override { return new ProjectionTestCanvas(mDrawCounter); }
472 sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500473 void onCopyOnWrite(ContentChangeMode) override {}
Mike Reed6acfe162016-11-18 17:21:09 -0500474 int* mDrawCounter;
Leon Scroggins III71195ab2018-02-08 17:14:28 -0500475 void onWritePixels(const SkPixmap&, int x, int y) {}
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500476 };
477
John Reck1bcacfd2017-11-03 10:12:19 -0700478 auto receiverBackground = TestUtils::createSkiaNode(
479 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500480 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700481 properties.setProjectionReceiver(true);
482 // scroll doesn't apply to background, so undone via translationX/Y
483 // NOTE: translationX/Y only! no other transform properties may be set for a proj
484 // receiver!
485 properties.setTranslationX(SCROLL_X);
486 properties.setTranslationY(SCROLL_Y);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500487
John Reck1bcacfd2017-11-03 10:12:19 -0700488 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
489 },
490 "B"); // B
491 auto projectingRipple = TestUtils::createSkiaNode(
492 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500493 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700494 properties.setProjectBackwards(true);
495 properties.setClipToBounds(false);
496 canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
497 },
498 "R"); // R
499 auto child = TestUtils::createSkiaNode(
500 100, 100, 300, 300,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500501 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700502 canvas.drawRenderNode(projectingRipple.get());
503 canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
504 },
505 "C"); // C
506 auto parent = TestUtils::createSkiaNode(
507 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500508 [&receiverBackground, &child](RenderProperties& properties,
John Reck1bcacfd2017-11-03 10:12:19 -0700509 SkiaRecordingCanvas& canvas) {
510 // Set a rect outline for the projecting ripple to be masked against.
511 properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
512 canvas.translate(-SCROLL_X,
513 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
514 canvas.drawRenderNode(receiverBackground.get());
515 canvas.drawRenderNode(child.get());
516 },
517 "A"); // A
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500518
John Reck1bcacfd2017-11-03 10:12:19 -0700519 // prepareTree is required to find, which receivers have backward projected nodes
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500520 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700521 std::unique_ptr<CanvasContext> canvasContext(
522 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500523 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
524 DamageAccumulator damageAccumulator;
525 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500526 parent->prepareTree(info);
527
Mike Reed6acfe162016-11-18 17:21:09 -0500528 int drawCounter = 0;
John Reck1bcacfd2017-11-03 10:12:19 -0700529 // set a layer after prepareTree to avoid layer logic there
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500530 child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
Mike Reed6acfe162016-11-18 17:21:09 -0500531 sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500532 child->setLayerSurface(surfaceLayer1);
533 Matrix4 windowTransform;
534 windowTransform.loadTranslate(100, 100, 0);
535 child->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
536
537 LayerUpdateQueue layerUpdateQueue;
538 layerUpdateQueue.enqueueLayerWithDamage(child.get(),
John Reck1bcacfd2017-11-03 10:12:19 -0700539 android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
Stan Ilieve9d00122017-09-19 12:07:10 -0400540 auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
Peiyong Lin1f6aa122018-09-10 16:28:08 -0700541 pipeline->renderLayersImpl(layerUpdateQueue, true);
John Reck1bcacfd2017-11-03 10:12:19 -0700542 EXPECT_EQ(1, drawCounter); // assert index 0 is drawn on the layer
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500543
Mike Reed6acfe162016-11-18 17:21:09 -0500544 RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
545 surfaceLayer1->getCanvas()->drawDrawable(&drawable);
546 EXPECT_EQ(4, drawCounter);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500547
548 // clean up layer pointer, so we can safely destruct RenderNode
549 child->setLayerSurface(nullptr);
550}
551
552RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
553 /* R is backward projected on B.
554 A
555 / \
556 B C
557 |
558 R
559 */
560 static const int SCROLL_X = 500000;
561 static const int SCROLL_Y = 0;
562 static const int CANVAS_WIDTH = 400;
563 static const int CANVAS_HEIGHT = 400;
564 class ProjectionChildScrollTestCanvas : public SkCanvas {
565 public:
566 ProjectionChildScrollTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
567 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
Stan Iliev52771272016-11-17 09:54:38 -0500568 EXPECT_EQ(0, mDrawCounter++);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500569 EXPECT_TRUE(getTotalMatrix().isIdentity());
570 }
571 void onDrawOval(const SkRect&, const SkPaint&) override {
Stan Iliev52771272016-11-17 09:54:38 -0500572 EXPECT_EQ(1, mDrawCounter++);
573 EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500574 EXPECT_TRUE(getTotalMatrix().isIdentity());
575 }
Stan Iliev52771272016-11-17 09:54:38 -0500576 int mDrawCounter = 0;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500577 };
578
John Reck1bcacfd2017-11-03 10:12:19 -0700579 auto receiverBackground = TestUtils::createSkiaNode(
580 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500581 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700582 properties.setProjectionReceiver(true);
583 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
584 },
585 "B"); // B
586 auto projectingRipple = TestUtils::createSkiaNode(
587 0, 0, 200, 200,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500588 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700589 // scroll doesn't apply to background, so undone via translationX/Y
590 // NOTE: translationX/Y only! no other transform properties may be set for a proj
591 // receiver!
592 properties.setTranslationX(SCROLL_X);
593 properties.setTranslationY(SCROLL_Y);
594 properties.setProjectBackwards(true);
595 properties.setClipToBounds(false);
596 canvas.drawOval(0, 0, 200, 200, SkPaint());
597 },
598 "R"); // R
599 auto child = TestUtils::createSkiaNode(
600 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500601 [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700602 // Record time clip will be ignored by projectee
603 canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500604
John Reck1bcacfd2017-11-03 10:12:19 -0700605 canvas.translate(-SCROLL_X,
606 -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
607 canvas.drawRenderNode(projectingRipple.get());
608 },
609 "C"); // C
610 auto parent =
611 TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
612 [&receiverBackground, &child](RenderProperties& properties,
613 SkiaRecordingCanvas& canvas) {
614 canvas.drawRenderNode(receiverBackground.get());
615 canvas.drawRenderNode(child.get());
616 },
617 "A"); // A
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500618
John Reck1bcacfd2017-11-03 10:12:19 -0700619 // prepareTree is required to find, which receivers have backward projected nodes
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500620 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700621 std::unique_ptr<CanvasContext> canvasContext(
622 CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500623 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
624 DamageAccumulator damageAccumulator;
625 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500626 parent->prepareTree(info);
627
Mike Reed6acfe162016-11-18 17:21:09 -0500628 std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500629 RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
630 canvas->drawDrawable(&drawable);
Stan Iliev52771272016-11-17 09:54:38 -0500631 EXPECT_EQ(2, canvas->mDrawCounter);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500632}
633
634namespace {
John Reck1bcacfd2017-11-03 10:12:19 -0700635static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500636 ContextFactory contextFactory;
John Reck1bcacfd2017-11-03 10:12:19 -0700637 std::unique_ptr<CanvasContext> canvasContext(
638 CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory));
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500639 TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
640 DamageAccumulator damageAccumulator;
641 info.damageAccumulator = &damageAccumulator;
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500642 renderNode->prepareTree(info);
643
John Reck1bcacfd2017-11-03 10:12:19 -0700644 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500645 ZReorderCanvas canvas(100, 100);
646 RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
647 canvas.drawDrawable(&drawable);
648 return canvas.getIndex();
649}
650}
651
652RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) {
653 /* R is backward projected on B
654 A
655 / \
656 B C
657 |
658 R
659 */
John Reck1bcacfd2017-11-03 10:12:19 -0700660 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
661 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500662 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
663 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700664 }); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500665 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
666 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
667 props.setProjectBackwards(true);
668 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700669 }); // nodeR
670 }); // nodeC
671 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500672 EXPECT_EQ(3, drawNode(renderThread, nodeA));
673}
674
675RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) {
676 /* R is backward projected on E
677 A
678 / | \
679 / | \
680 B C E
681 |
682 R
683 */
John Reck1bcacfd2017-11-03 10:12:19 -0700684 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
685 SkiaRecordingCanvas& canvas) {
686 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500687 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700688 drawOrderedNode(&canvas, 3, [](RenderProperties& props,
689 SkiaRecordingCanvas& canvas) { // drawn as 2
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500690 props.setProjectBackwards(true);
691 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700692 }); // nodeR
693 }); // nodeC
694 drawOrderedNode(&canvas, 2,
695 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // drawn as 3
696 props.setProjectionReceiver(true);
697 }); // nodeE
698 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500699 EXPECT_EQ(4, drawNode(renderThread, nodeA));
700}
701
702RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) {
703 /* R is backward projected without receiver
704 A
705 / \
706 B C
707 |
708 R
709 */
John Reck1bcacfd2017-11-03 10:12:19 -0700710 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
711 SkiaRecordingCanvas& canvas) {
712 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500713 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
714 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700715 // not having a projection receiver is an undefined behavior
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500716 props.setProjectBackwards(true);
717 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700718 }); // nodeR
719 }); // nodeC
720 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500721 EXPECT_EQ(2, drawNode(renderThread, nodeA));
722}
723
724RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) {
725 /* R is backward projected on C
726 A
727 / \
728 B C
729 |
730 R
731 */
John Reck1bcacfd2017-11-03 10:12:19 -0700732 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
733 SkiaRecordingCanvas& canvas) {
734 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500735 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
736 props.setProjectionReceiver(true);
737 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
738 props.setProjectBackwards(true);
739 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700740 }); // nodeR
741 }); // nodeC
742 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500743 EXPECT_EQ(3, drawNode(renderThread, nodeA));
744}
745
746RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) {
747 /* R is backward projected on R
748 A
749 / \
750 B C
751 |
752 R
753 */
John Reck1bcacfd2017-11-03 10:12:19 -0700754 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
755 SkiaRecordingCanvas& canvas) {
756 drawOrderedNode(&canvas, 0, nullptr); // nodeB
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500757 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
758 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700759 // having a node that is projected on itself is an undefined/unexpected behavior
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500760 props.setProjectionReceiver(true);
761 props.setProjectBackwards(true);
762 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700763 }); // nodeR
764 }); // nodeC
765 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500766 EXPECT_EQ(2, drawNode(renderThread, nodeA));
767}
768
John Reck1bcacfd2017-11-03 10:12:19 -0700769// Note: the outcome for this test is different in HWUI
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500770RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
771 /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
772 A
773 /|\
774 / | \
775 B C R
776 */
John Reck1bcacfd2017-11-03 10:12:19 -0700777 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
778 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500779 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
780 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700781 }); // nodeB
782 drawOrderedNode(&canvas, 1,
783 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500784 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
785 props.setProjectBackwards(true);
786 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700787 }); // nodeR
788 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500789 EXPECT_EQ(2, drawNode(renderThread, nodeA));
790}
791
792RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling2) {
793 /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
794 A
795 |
796 G
797 /|\
798 / | \
799 B C R
800 */
John Reck1bcacfd2017-11-03 10:12:19 -0700801 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
802 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500803 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
804 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
805 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700806 }); // nodeB
807 drawOrderedNode(&canvas, 2,
808 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500809 drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
810 props.setProjectBackwards(true);
811 props.setClipToBounds(false);
John Reck1bcacfd2017-11-03 10:12:19 -0700812 }); // nodeR
813 }); // nodeG
814 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500815 EXPECT_EQ(3, drawNode(renderThread, nodeA));
816}
817
818RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderGrandparentReceivable) {
819 /* R is backward projected on B
820 A
821 |
822 B
823 |
824 C
825 |
826 R
827 */
John Reck1bcacfd2017-11-03 10:12:19 -0700828 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
829 SkiaRecordingCanvas& canvas) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500830 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
831 props.setProjectionReceiver(true);
832 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -0700833 drawOrderedNode(&canvas, 2,
834 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
835 props.setProjectBackwards(true);
836 props.setClipToBounds(false);
837 }); // nodeR
838 }); // nodeC
839 }); // nodeB
840 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500841 EXPECT_EQ(3, drawNode(renderThread, nodeA));
842}
843
844RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivables) {
845 /* B and G are receivables, R is backward projected
846 A
847 / \
848 B C
849 / \
850 G R
851 */
John Reck1bcacfd2017-11-03 10:12:19 -0700852 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
853 SkiaRecordingCanvas& canvas) {
854 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500855 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700856 }); // nodeB
857 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
858 drawOrderedNode(&canvas, 3,
859 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
860 props.setProjectionReceiver(true);
861 }); // nodeG
862 drawOrderedNode(&canvas, 1,
863 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
864 props.setProjectBackwards(true);
865 props.setClipToBounds(false);
866 }); // nodeR
867 }); // nodeC
868 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500869 EXPECT_EQ(4, drawNode(renderThread, nodeA));
870}
871
872RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesLikelyScenario) {
873 /* B and G are receivables, G is backward projected
874 A
875 / \
876 B C
877 / \
878 G R
879 */
John Reck1bcacfd2017-11-03 10:12:19 -0700880 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
881 SkiaRecordingCanvas& canvas) {
882 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500883 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700884 }); // nodeB
885 drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
886 drawOrderedNode(&canvas, 1,
887 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
888 props.setProjectionReceiver(true);
889 props.setProjectBackwards(true);
890 props.setClipToBounds(false);
891 }); // nodeG
892 drawOrderedNode(&canvas, 3,
893 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
894 }); // nodeR
895 }); // nodeC
896 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500897 EXPECT_EQ(4, drawNode(renderThread, nodeA));
898}
899
900RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesDeeper) {
901 /* B and G are receivables, R is backward projected
902 A
903 / \
904 B C
905 / \
906 G D
907 |
908 R
909 */
John Reck1bcacfd2017-11-03 10:12:19 -0700910 auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
911 SkiaRecordingCanvas& canvas) {
912 drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500913 props.setProjectionReceiver(true);
John Reck1bcacfd2017-11-03 10:12:19 -0700914 }); // nodeB
915 drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
916 drawOrderedNode(&canvas, 2,
917 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
918 props.setProjectionReceiver(true);
919 }); // nodeG
920 drawOrderedNode(&canvas, 4,
921 [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // D
922 drawOrderedNode(&canvas, 3, [](RenderProperties& props,
923 SkiaRecordingCanvas& canvas) { // R
924 props.setProjectBackwards(true);
925 props.setClipToBounds(false);
926 }); // nodeR
927 }); // nodeD
928 }); // nodeC
929 }); // nodeA
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500930 EXPECT_EQ(5, drawNode(renderThread, nodeA));
Stan Iliev021693b2016-10-17 16:26:15 -0400931}
Stan Iliev52771272016-11-17 09:54:38 -0500932
933RENDERTHREAD_TEST(RenderNodeDrawable, simple) {
934 static const int CANVAS_WIDTH = 100;
935 static const int CANVAS_HEIGHT = 200;
936 class SimpleTestCanvas : public TestCanvasBase {
937 public:
John Reck1bcacfd2017-11-03 10:12:19 -0700938 SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
Stan Iliev52771272016-11-17 09:54:38 -0500939 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
940 EXPECT_EQ(0, mDrawCounter++);
941 }
942 void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
943 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,
951 SkPaint());
952 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) {
1027 SkPaint paint;
1028 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) {
John Reck1bcacfd2017-11-03 10:12:19 -07001035 SkPaint paint;
1036 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
Stan Iliev7e100e92018-01-22 10:36:33 -05001051// Verify that layers are composed with kLow_SkFilterQuality filter quality.
1052RENDERTHREAD_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) {}
1060 void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1061 const SkPaint* paint, SrcRectConstraint constraint) override {
1062 mDrawCounter++;
1063 EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality());
1064 }
1065 };
1066
1067 auto layerNode = TestUtils::createSkiaNode(
1068 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
1069 [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
1070 canvas.drawPaint(SkPaint());
1071 });
1072
1073 layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
1074 layerNode->setLayerSurface(SkSurface::MakeRasterN32Premul(LAYER_WIDTH, LAYER_HEIGHT));
1075
1076 FrameTestCanvas canvas;
1077 RenderNodeDrawable drawable(layerNode.get(), &canvas, true);
1078 canvas.drawDrawable(&drawable);
1079 EXPECT_EQ(1, canvas.mDrawCounter); //make sure the layer was composed
1080
1081 // clean up layer pointer, so we can safely destruct RenderNode
1082 layerNode->setLayerSurface(nullptr);
1083}
1084
Stan Ilievd7410f72017-04-04 15:23:54 -04001085TEST(ReorderBarrierDrawable, testShadowMatrix) {
1086 static const int CANVAS_WIDTH = 100;
1087 static const int CANVAS_HEIGHT = 100;
1088 static const float TRANSLATE_X = 11.0f;
1089 static const float TRANSLATE_Y = 22.0f;
1090 static const float CASTER_X = 40.0f;
1091 static const float CASTER_Y = 40.0f;
1092 static const float CASTER_WIDTH = 20.0f;
1093 static const float CASTER_HEIGHT = 20.0f;
1094
Stan Ilievd7410f72017-04-04 15:23:54 -04001095 class ShadowTestCanvas : public SkCanvas {
1096 public:
1097 ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
Stan Iliev54d70322018-06-14 18:00:10 -04001098 int getDrawCounter() { return mDrawCounter; }
Stan Ilievd7410f72017-04-04 15:23:54 -04001099
1100 virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
1101 // expect to draw 2 RenderNodeDrawable, 1 StartReorderBarrierDrawable,
1102 // 1 EndReorderBarrierDrawable
1103 mDrawCounter++;
1104 SkCanvas::onDrawDrawable(drawable, matrix);
1105 }
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
Stan Iliev54d70322018-06-14 18:00:10 -04001113 virtual void didSetMatrix(const SkMatrix& 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.
1117 EXPECT_TRUE(matrix.isIdentity());
1118 EXPECT_TRUE(getTotalMatrix().isIdentity());
1119 }
1120
1121 virtual void didConcat(const SkMatrix& matrix) override {
1122 mDrawCounter++;
1123 if (mFirstDidConcat) {
1124 // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
1125 mFirstDidConcat = false;
1126 EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
1127 matrix);
1128 EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
1129 getTotalMatrix());
1130 } else {
1131 // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
1132 EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
1133 matrix);
1134 EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
1135 getTotalMatrix());
1136 }
Stan Ilievd7410f72017-04-04 15:23:54 -04001137 }
John Reck1bcacfd2017-11-03 10:12:19 -07001138
Stan Ilievd7410f72017-04-04 15:23:54 -04001139 protected:
1140 int mDrawCounter = 0;
Stan Iliev54d70322018-06-14 18:00:10 -04001141 private:
1142 bool mFirstDidConcat = true;
Stan Ilievd7410f72017-04-04 15:23:54 -04001143 };
1144
John Reck1bcacfd2017-11-03 10:12:19 -07001145 auto parent = TestUtils::createSkiaNode(
1146 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
Stan Ilievd7410f72017-04-04 15:23:54 -04001147 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
John Reck1bcacfd2017-11-03 10:12:19 -07001148 canvas.translate(TRANSLATE_X, TRANSLATE_Y);
1149 canvas.insertReorderBarrier(true);
Stan Ilievd7410f72017-04-04 15:23:54 -04001150
John Reck1bcacfd2017-11-03 10:12:19 -07001151 auto node = TestUtils::createSkiaNode(
1152 CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT,
1153 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1154 props.setElevation(42);
1155 props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
1156 props.mutableOutline().setShouldClip(true);
1157 });
1158 canvas.drawRenderNode(node.get());
1159 canvas.insertReorderBarrier(false);
1160 });
Stan Ilievd7410f72017-04-04 15:23:54 -04001161
John Reck1bcacfd2017-11-03 10:12:19 -07001162 // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
Stan Ilievd7410f72017-04-04 15:23:54 -04001163 ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
1164 RenderNodeDrawable drawable(parent.get(), &canvas, false);
1165 canvas.drawDrawable(&drawable);
Stan Iliev54d70322018-06-14 18:00:10 -04001166 EXPECT_EQ(9, canvas.getDrawCounter());
Stan Iliev65e678f2018-02-07 14:07:30 -05001167}
1168
1169// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
1170RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
1171 static const int CANVAS_WIDTH = 100;
1172 static const int CANVAS_HEIGHT = 200;
1173 class VectorDrawableTestCanvas : public TestCanvasBase {
1174 public:
1175 VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
1176 void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1177 const SkPaint* paint, SrcRectConstraint constraint) override {
1178 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 }
1190 };
1191
1192 VectorDrawable::Group* group = new VectorDrawable::Group();
1193 sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
1194 vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH/10, CANVAS_HEIGHT/10);
1195
1196 auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
1197 [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1198 vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH,
1199 CANVAS_HEIGHT));
1200 canvas.drawVectorDrawable(vectorDrawable.get());
1201 vectorDrawable->mutateStagingProperties()->setBounds(SkRect::MakeWH(CANVAS_WIDTH/2,
1202 CANVAS_HEIGHT));
1203 canvas.drawVectorDrawable(vectorDrawable.get());
1204 });
1205
1206 VectorDrawableTestCanvas canvas;
1207 RenderNodeDrawable drawable(node.get(), &canvas, true);
1208 canvas.drawDrawable(&drawable);
1209 EXPECT_EQ(2, canvas.mDrawCounter);
1210}