• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include <VectorDrawable.h>
18 #include <gtest/gtest.h>
19 
20 #include <SkClipStack.h>
21 #include <SkSurface_Base.h>
22 #include <string.h>
23 #include "AnimationContext.h"
24 #include "DamageAccumulator.h"
25 #include "FatalTestCanvas.h"
26 #include "IContextFactory.h"
27 #include "RecordingCanvas.h"
28 #include "SkiaCanvas.h"
29 #include "pipeline/skia/SkiaDisplayList.h"
30 #include "pipeline/skia/SkiaOpenGLPipeline.h"
31 #include "pipeline/skia/SkiaPipeline.h"
32 #include "pipeline/skia/SkiaRecordingCanvas.h"
33 #include "renderthread/CanvasContext.h"
34 #include "tests/common/TestUtils.h"
35 #include "utils/Color.h"
36 
37 using namespace android;
38 using namespace android::uirenderer;
39 using namespace android::uirenderer::renderthread;
40 using namespace android::uirenderer::skiapipeline;
41 
TEST(RenderNodeDrawable,create)42 TEST(RenderNodeDrawable, create) {
43     auto rootNode =
44             TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
45                 canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
46             });
47 
48     DisplayListData skLiteDL;
49     RecordingCanvas canvas;
50     canvas.reset(&skLiteDL, SkIRect::MakeWH(1, 1));
51     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 
59 namespace {
60 
drawOrderedRect(Canvas * canvas,uint8_t expectedDrawOrder)61 static 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);
66 }
67 
drawOrderedNode(Canvas * canvas,uint8_t expectedDrawOrder,float z)68 static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
69     auto node = TestUtils::createSkiaNode(
70             0, 0, 100, 100,
71             [expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) {
72                 drawOrderedRect(&canvas, expectedDrawOrder);
73                 props.setTranslationZ(z);
74             });
75     canvas->drawRenderNode(node.get());  // canvas takes reference/sole ownership
76 }
77 
drawOrderedNode(Canvas * canvas,uint8_t expectedDrawOrder,std::function<void (RenderProperties & props,SkiaRecordingCanvas & canvas)> setup)78 static void drawOrderedNode(
79         Canvas* canvas, uint8_t expectedDrawOrder,
80         std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup) {
81     auto node = TestUtils::createSkiaNode(
82             0, 0, 100, 100,
83             [expectedDrawOrder, setup](RenderProperties& props, SkiaRecordingCanvas& canvas) {
84                 drawOrderedRect(&canvas, expectedDrawOrder);
85                 if (setup) {
86                     setup(props, canvas);
87                 }
88             });
89     canvas->drawRenderNode(node.get());  // canvas takes reference/sole ownership
90 }
91 
92 class ZReorderCanvas : public SkCanvas {
93 public:
ZReorderCanvas(int width,int height)94     ZReorderCanvas(int width, int height) : SkCanvas(width, height) {}
onDrawRect(const SkRect & rect,const SkPaint & paint)95     void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
96         int expectedOrder = SkColorGetB(paint.getColor());  // extract order from blue channel
97         EXPECT_EQ(expectedOrder, mDrawCounter++) << "An op was drawn out of order";
98     }
getIndex()99     int getIndex() { return mDrawCounter; }
100 
101 protected:
102     int mDrawCounter = 0;
103 };
104 
105 }  // end anonymous namespace
106 
TEST(RenderNodeDrawable,zReorder)107 TEST(RenderNodeDrawable, zReorder) {
108     auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
109                                                                SkiaRecordingCanvas& canvas) {
110         canvas.insertReorderBarrier(true);
111         canvas.insertReorderBarrier(false);
112         drawOrderedNode(&canvas, 0, 10.0f);  // in reorder=false at this point, so played inorder
113         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);
123         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
125         drawOrderedRect(&canvas, 11);
126         drawOrderedNode(&canvas, 10, -1.0f);
127         canvas.insertReorderBarrier(false);
128         canvas.insertReorderBarrier(true);  // test with two empty reorder sections
129         canvas.insertReorderBarrier(true);
130         canvas.insertReorderBarrier(false);
131         drawOrderedRect(&canvas, 12);
132     });
133 
134     // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
135     ZReorderCanvas canvas(100, 100);
136     RenderNodeDrawable drawable(parent.get(), &canvas, false);
137     canvas.drawDrawable(&drawable);
138     EXPECT_EQ(13, canvas.getIndex());
139 }
140 
TEST(RenderNodeDrawable,composeOnLayer)141 TEST(RenderNodeDrawable, composeOnLayer) {
142     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 
147     auto rootNode = TestUtils::createSkiaNode(
148             0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
149                 recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
150             });
151 
152     // attach a layer to the render node
153     auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
154     auto canvas2 = surfaceLayer->getCanvas();
155     canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
156     rootNode->setLayerSurface(surfaceLayer);
157 
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 
170     rootNode->setLayerSurface(sk_sp<SkSurface>());
171 }
172 
173 namespace {
getRecorderClipBounds(const SkiaRecordingCanvas & recorder)174 static SkRect getRecorderClipBounds(const SkiaRecordingCanvas& recorder) {
175     SkRect clipBounds;
176     recorder.getClipBounds(&clipBounds);
177     return clipBounds;
178 }
179 
getRecorderMatrix(const SkiaRecordingCanvas & recorder)180 static SkMatrix getRecorderMatrix(const SkiaRecordingCanvas& recorder) {
181     SkMatrix matrix;
182     recorder.getMatrix(&matrix);
183     return matrix;
184 }
185 }
186 
TEST(RenderNodeDrawable,saveLayerClipAndMatrixRestore)187 TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) {
188     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 
193     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());
198 
199                 // 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());
203 
204                 recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
205                 ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
206 
207                 recorder.translate(300.0f, 400.0f);
208                 EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
209 
210                 recorder.restore();
211                 ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
212                 EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
213 
214                 SkPaint paint;
215                 paint.setAntiAlias(true);
216                 paint.setColor(SK_ColorGREEN);
217                 recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
218             });
219 
220     RenderNodeDrawable drawable(rootNode.get(), &canvas, true);
221     canvas.drawDrawable(&drawable);
222     ASSERT_EQ(SK_ColorGREEN, TestUtils::getColor(surface, 200, 600));
223 }
224 
225 namespace {
226 class ContextFactory : public IContextFactory {
227 public:
createAnimationContext(renderthread::TimeLord & clock)228     virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
229         return new AnimationContext(clock);
230     }
231 };
232 }  // end anonymous namespace
233 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorder)234 RENDERTHREAD_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 {
241             const int index = mDrawCounter++;
242             SkMatrix expectedMatrix;
243             ;
244             switch (index) {
245                 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();
266             }
267             EXPECT_EQ(expectedMatrix, getTotalMatrix());
268         }
269 
270         int getIndex() { return mDrawCounter; }
271 
272     protected:
273         int mDrawCounter = 0;
274     };
275 
276     /**
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      */
284     auto receiverBackground = TestUtils::createSkiaNode(
285             0, 0, 100, 100,
286             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
287                 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);
293 
294                 SkPaint paint;
295                 paint.setColor(SK_ColorWHITE);
296                 canvas.drawRect(0, 0, 100, 100, paint);
297             },
298             "B");
299 
300     auto projectingRipple = TestUtils::createSkiaNode(
301             50, 0, 100, 50,
302             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
303                 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,
312             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
313                 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);
325 
326                 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");
334     ContextFactory contextFactory;
335     std::unique_ptr<CanvasContext> canvasContext(
336             CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
337     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
338     DamageAccumulator damageAccumulator;
339     info.damageAccumulator = &damageAccumulator;
340     parent->prepareTree(info);
341 
342     // 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
346 
347     // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
348     ProjectionTestCanvas canvas(100, 100);
349     RenderNodeDrawable drawable(parent.get(), &canvas, true);
350     canvas.drawDrawable(&drawable);
351     EXPECT_EQ(3, canvas.getIndex());
352 }
353 
RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable,emptyReceiver)354 RENDERTHREAD_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 { mDrawCounter++; }
359 
360         int getDrawCounter() { return mDrawCounter; }
361 
362     private:
363         int mDrawCounter = 0;
364     };
365 
366     auto receiverBackground = TestUtils::createSkiaNode(
367             0, 0, 100, 100,
368             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
369                 properties.setProjectionReceiver(true);
370             },
371             "B");  // a receiver with an empty display list
372 
373     auto projectingRipple = TestUtils::createSkiaNode(
374             0, 0, 100, 100,
375             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
376                 properties.setProjectBackwards(true);
377                 properties.setClipToBounds(false);
378                 SkPaint paint;
379                 canvas.drawRect(0, 0, 100, 100, paint);
380             },
381             "P");
382     auto child = TestUtils::createSkiaNode(
383             0, 0, 100, 100,
384             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
385                 SkPaint paint;
386                 canvas.drawRect(0, 0, 100, 100, paint);
387                 canvas.drawRenderNode(projectingRipple.get());
388             },
389             "C");
390     auto parent =
391             TestUtils::createSkiaNode(0, 0, 100, 100,
392                                       [&receiverBackground, &child](RenderProperties& properties,
393                                                                     SkiaRecordingCanvas& canvas) {
394                                           canvas.drawRenderNode(receiverBackground.get());
395                                           canvas.drawRenderNode(child.get());
396                                       },
397                                       "A");
398     ContextFactory contextFactory;
399     std::unique_ptr<CanvasContext> canvasContext(
400             CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
401     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
402     DamageAccumulator damageAccumulator;
403     info.damageAccumulator = &damageAccumulator;
404     parent->prepareTree(info);
405 
406     // parent(A)             -> (receiverBackground, child)
407     // child(C)              -> (rect[0, 0, 100, 100], projectingRipple)
408     // projectingRipple(P)   -> (rect[0, 0, 100, 100]) -> projects backwards
409     // receiverBackground(B) -> (empty) -> projection receiver
410 
411     // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
412     ProjectionTestCanvas canvas(100, 100);
413     RenderNodeDrawable drawable(parent.get(), &canvas, true);
414     canvas.drawDrawable(&drawable);
415     EXPECT_EQ(2, canvas.getDrawCounter());
416 }
417 
RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable,projectionHwLayer)418 RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) {
419     /* R is backward projected on B and C is a layer.
420                 A
421                / \
422               B   C
423                   |
424                   R
425     */
426     static const int SCROLL_X = 5;
427     static const int SCROLL_Y = 10;
428     static const int CANVAS_WIDTH = 400;
429     static const int CANVAS_HEIGHT = 400;
430     static const int LAYER_WIDTH = 200;
431     static const int LAYER_HEIGHT = 200;
432     class ProjectionTestCanvas : public SkCanvas {
433     public:
434         ProjectionTestCanvas(int* drawCounter)
435                 : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT), mDrawCounter(drawCounter) {}
436         void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
437                        const SkPaint&) override {
438             EXPECT_EQ(0, (*mDrawCounter)++);  // part of painting the layer
439             EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT),
440                       TestUtils::getClipBounds(this));
441         }
442         void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
443             EXPECT_EQ(1, (*mDrawCounter)++);
444             EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT),
445                       TestUtils::getClipBounds(this));
446         }
447         void onDrawOval(const SkRect&, const SkPaint&) override {
448             EXPECT_EQ(2, (*mDrawCounter)++);
449             SkMatrix expectedMatrix;
450             expectedMatrix.setTranslate(100 - SCROLL_X, 100 - SCROLL_Y);
451             EXPECT_EQ(expectedMatrix, getTotalMatrix());
452             EXPECT_EQ(SkRect::MakeLTRB(-85, -80, 295, 300), TestUtils::getLocalClipBounds(this));
453         }
454         int* mDrawCounter;
455     };
456 
457     class ProjectionLayer : public SkSurface_Base {
458     public:
459         ProjectionLayer(int* drawCounter)
460                 : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
461                 , mDrawCounter(drawCounter) {}
462         virtual sk_sp<SkImage> onNewImageSnapshot(const SkIRect* bounds) override {
463             EXPECT_EQ(3, (*mDrawCounter)++);
464             EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
465                                        300 - SCROLL_Y),
466                       TestUtils::getClipBounds(this->getCanvas()));
467             return nullptr;
468         }
469         SkCanvas* onNewCanvas() override { return new ProjectionTestCanvas(mDrawCounter); }
470         sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
471         void onCopyOnWrite(ContentChangeMode) override {}
472         int* mDrawCounter;
473         void onWritePixels(const SkPixmap&, int x, int y) {}
474     };
475 
476     auto receiverBackground = TestUtils::createSkiaNode(
477             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
478             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
479                 properties.setProjectionReceiver(true);
480                 // scroll doesn't apply to background, so undone via translationX/Y
481                 // NOTE: translationX/Y only! no other transform properties may be set for a proj
482                 // receiver!
483                 properties.setTranslationX(SCROLL_X);
484                 properties.setTranslationY(SCROLL_Y);
485 
486                 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
487             },
488             "B");  // B
489     auto projectingRipple = TestUtils::createSkiaNode(
490             0, 0, LAYER_WIDTH, LAYER_HEIGHT,
491             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
492                 properties.setProjectBackwards(true);
493                 properties.setClipToBounds(false);
494                 canvas.drawOval(100, 100, 300, 300, SkPaint());  // drawn mostly out of layer bounds
495             },
496             "R");  // R
497     auto child = TestUtils::createSkiaNode(
498             100, 100, 300, 300,
499             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
500                 canvas.drawRenderNode(projectingRipple.get());
501                 canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
502             },
503             "C");  // C
504     auto parent = TestUtils::createSkiaNode(
505             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
506             [&receiverBackground, &child](RenderProperties& properties,
507                                           SkiaRecordingCanvas& canvas) {
508                 // Set a rect outline for the projecting ripple to be masked against.
509                 properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
510                 canvas.translate(-SCROLL_X,
511                                  -SCROLL_Y);  // Apply scroll (note: bg undoes this internally)
512                 canvas.drawRenderNode(receiverBackground.get());
513                 canvas.drawRenderNode(child.get());
514             },
515             "A");  // A
516 
517     // prepareTree is required to find, which receivers have backward projected nodes
518     ContextFactory contextFactory;
519     std::unique_ptr<CanvasContext> canvasContext(
520             CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
521     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
522     DamageAccumulator damageAccumulator;
523     info.damageAccumulator = &damageAccumulator;
524     parent->prepareTree(info);
525 
526     int drawCounter = 0;
527     // set a layer after prepareTree to avoid layer logic there
528     child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
529     sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
530     child->setLayerSurface(surfaceLayer1);
531     Matrix4 windowTransform;
532     windowTransform.loadTranslate(100, 100, 0);
533     child->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
534 
535     LayerUpdateQueue layerUpdateQueue;
536     layerUpdateQueue.enqueueLayerWithDamage(child.get(),
537                                             android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
538     auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
539     pipeline->renderLayersImpl(layerUpdateQueue, true);
540     EXPECT_EQ(1, drawCounter);  // assert index 0 is drawn on the layer
541 
542     RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
543     surfaceLayer1->getCanvas()->drawDrawable(&drawable);
544     EXPECT_EQ(4, drawCounter);
545 
546     // clean up layer pointer, so we can safely destruct RenderNode
547     child->setLayerSurface(nullptr);
548 }
549 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionChildScroll)550 RENDERTHREAD_TEST(RenderNodeDrawable, projectionChildScroll) {
551     /* R is backward projected on B.
552                 A
553                / \
554               B   C
555                   |
556                   R
557     */
558     static const int SCROLL_X = 500000;
559     static const int SCROLL_Y = 0;
560     static const int CANVAS_WIDTH = 400;
561     static const int CANVAS_HEIGHT = 400;
562     class ProjectionChildScrollTestCanvas : public SkCanvas {
563     public:
564         ProjectionChildScrollTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
565         void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
566             EXPECT_EQ(0, mDrawCounter++);
567             EXPECT_TRUE(getTotalMatrix().isIdentity());
568         }
569         void onDrawOval(const SkRect&, const SkPaint&) override {
570             EXPECT_EQ(1, mDrawCounter++);
571             EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
572             EXPECT_TRUE(getTotalMatrix().isIdentity());
573         }
574         int mDrawCounter = 0;
575     };
576 
577     auto receiverBackground = TestUtils::createSkiaNode(
578             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
579             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
580                 properties.setProjectionReceiver(true);
581                 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
582             },
583             "B");  // B
584     auto projectingRipple = TestUtils::createSkiaNode(
585             0, 0, 200, 200,
586             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
587                 // scroll doesn't apply to background, so undone via translationX/Y
588                 // NOTE: translationX/Y only! no other transform properties may be set for a proj
589                 // receiver!
590                 properties.setTranslationX(SCROLL_X);
591                 properties.setTranslationY(SCROLL_Y);
592                 properties.setProjectBackwards(true);
593                 properties.setClipToBounds(false);
594                 canvas.drawOval(0, 0, 200, 200, SkPaint());
595             },
596             "R");  // R
597     auto child = TestUtils::createSkiaNode(
598             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
599             [&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
600                 // Record time clip will be ignored by projectee
601                 canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
602 
603                 canvas.translate(-SCROLL_X,
604                                  -SCROLL_Y);  // Apply scroll (note: bg undoes this internally)
605                 canvas.drawRenderNode(projectingRipple.get());
606             },
607             "C");  // C
608     auto parent =
609             TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
610                                       [&receiverBackground, &child](RenderProperties& properties,
611                                                                     SkiaRecordingCanvas& canvas) {
612                                           canvas.drawRenderNode(receiverBackground.get());
613                                           canvas.drawRenderNode(child.get());
614                                       },
615                                       "A");  // A
616 
617     // prepareTree is required to find, which receivers have backward projected nodes
618     ContextFactory contextFactory;
619     std::unique_ptr<CanvasContext> canvasContext(
620             CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
621     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
622     DamageAccumulator damageAccumulator;
623     info.damageAccumulator = &damageAccumulator;
624     parent->prepareTree(info);
625 
626     std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
627     RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
628     canvas->drawDrawable(&drawable);
629     EXPECT_EQ(2, canvas->mDrawCounter);
630 }
631 
632 namespace {
drawNode(RenderThread & renderThread,const sp<RenderNode> & renderNode)633 static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) {
634     ContextFactory contextFactory;
635     std::unique_ptr<CanvasContext> canvasContext(
636             CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory));
637     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
638     DamageAccumulator damageAccumulator;
639     info.damageAccumulator = &damageAccumulator;
640     renderNode->prepareTree(info);
641 
642     // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
643     ZReorderCanvas canvas(100, 100);
644     RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
645     canvas.drawDrawable(&drawable);
646     return canvas.getIndex();
647 }
648 }
649 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderProjectedInMiddle)650 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedInMiddle) {
651     /* R is backward projected on B
652                 A
653                / \
654               B   C
655                   |
656                   R
657     */
658     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
659                                                               SkiaRecordingCanvas& canvas) {
660         drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
661             props.setProjectionReceiver(true);
662         });  // nodeB
663         drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
664             drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
665                 props.setProjectBackwards(true);
666                 props.setClipToBounds(false);
667             });  // nodeR
668         });      // nodeC
669     });          // nodeA
670     EXPECT_EQ(3, drawNode(renderThread, nodeA));
671 }
672 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderProjectLast)673 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectLast) {
674     /* R is backward projected on E
675                   A
676                 / | \
677                /  |  \
678               B   C   E
679                   |
680                   R
681     */
682     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
683                                                               SkiaRecordingCanvas& canvas) {
684         drawOrderedNode(&canvas, 0, nullptr);  // nodeB
685         drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
686             drawOrderedNode(&canvas, 3, [](RenderProperties& props,
687                                            SkiaRecordingCanvas& canvas) {  // drawn as 2
688                 props.setProjectBackwards(true);
689                 props.setClipToBounds(false);
690             });  // nodeR
691         });      // nodeC
692         drawOrderedNode(&canvas, 2,
693                         [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // drawn as 3
694                             props.setProjectionReceiver(true);
695                         });  // nodeE
696     });                      // nodeA
697     EXPECT_EQ(4, drawNode(renderThread, nodeA));
698 }
699 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderNoReceivable)700 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderNoReceivable) {
701     /* R is backward projected without receiver
702                 A
703                / \
704               B   C
705                   |
706                   R
707     */
708     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
709                                                               SkiaRecordingCanvas& canvas) {
710         drawOrderedNode(&canvas, 0, nullptr);  // nodeB
711         drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
712             drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
713                 // not having a projection receiver is an undefined behavior
714                 props.setProjectBackwards(true);
715                 props.setClipToBounds(false);
716             });  // nodeR
717         });      // nodeC
718     });          // nodeA
719     EXPECT_EQ(2, drawNode(renderThread, nodeA));
720 }
721 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderParentReceivable)722 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderParentReceivable) {
723     /* R is backward projected on C
724                 A
725                / \
726               B   C
727                   |
728                   R
729     */
730     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
731                                                               SkiaRecordingCanvas& canvas) {
732         drawOrderedNode(&canvas, 0, nullptr);  // nodeB
733         drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
734             props.setProjectionReceiver(true);
735             drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
736                 props.setProjectBackwards(true);
737                 props.setClipToBounds(false);
738             });  // nodeR
739         });      // nodeC
740     });          // nodeA
741     EXPECT_EQ(3, drawNode(renderThread, nodeA));
742 }
743 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderSameNodeReceivable)744 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderSameNodeReceivable) {
745     /* R is backward projected on R
746                 A
747                / \
748               B   C
749                   |
750                   R
751     */
752     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
753                                                               SkiaRecordingCanvas& canvas) {
754         drawOrderedNode(&canvas, 0, nullptr);  // nodeB
755         drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
756             drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
757                 // having a node that is projected on itself is an undefined/unexpected behavior
758                 props.setProjectionReceiver(true);
759                 props.setProjectBackwards(true);
760                 props.setClipToBounds(false);
761             });  // nodeR
762         });      // nodeC
763     });          // nodeA
764     EXPECT_EQ(2, drawNode(renderThread, nodeA));
765 }
766 
767 // Note: the outcome for this test is different in HWUI
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderProjectedSibling)768 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
769     /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
770                 A
771                /|\
772               / | \
773              B  C  R
774     */
775     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
776                                                               SkiaRecordingCanvas& canvas) {
777         drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
778             props.setProjectionReceiver(true);
779         });  // nodeB
780         drawOrderedNode(&canvas, 1,
781                         [](RenderProperties& props, SkiaRecordingCanvas& canvas) {});  // nodeC
782         drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
783             props.setProjectBackwards(true);
784             props.setClipToBounds(false);
785         });  // nodeR
786     });      // nodeA
787     EXPECT_EQ(2, drawNode(renderThread, nodeA));
788 }
789 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderProjectedSibling2)790 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling2) {
791     /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
792                 A
793                 |
794                 G
795                /|\
796               / | \
797              B  C  R
798     */
799     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
800                                                               SkiaRecordingCanvas& canvas) {
801         drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
802             drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
803                 props.setProjectionReceiver(true);
804             });  // nodeB
805             drawOrderedNode(&canvas, 2,
806                             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {});  // nodeC
807             drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
808                 props.setProjectBackwards(true);
809                 props.setClipToBounds(false);
810             });  // nodeR
811         });      // nodeG
812     });          // nodeA
813     EXPECT_EQ(3, drawNode(renderThread, nodeA));
814 }
815 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderGrandparentReceivable)816 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderGrandparentReceivable) {
817     /* R is backward projected on B
818                 A
819                 |
820                 B
821                 |
822                 C
823                 |
824                 R
825     */
826     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
827                                                               SkiaRecordingCanvas& canvas) {
828         drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
829             props.setProjectionReceiver(true);
830             drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
831                 drawOrderedNode(&canvas, 2,
832                                 [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
833                                     props.setProjectBackwards(true);
834                                     props.setClipToBounds(false);
835                                 });  // nodeR
836             });                      // nodeC
837         });                          // nodeB
838     });                              // nodeA
839     EXPECT_EQ(3, drawNode(renderThread, nodeA));
840 }
841 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderTwoReceivables)842 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivables) {
843     /* B and G are receivables, R is backward projected
844                 A
845                / \
846               B   C
847                  / \
848                 G   R
849     */
850     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
851                                                               SkiaRecordingCanvas& canvas) {
852         drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // B
853             props.setProjectionReceiver(true);
854         });  // nodeB
855         drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // C
856             drawOrderedNode(&canvas, 3,
857                             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // G
858                                 props.setProjectionReceiver(true);
859                             });  // nodeG
860             drawOrderedNode(&canvas, 1,
861                             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // R
862                                 props.setProjectBackwards(true);
863                                 props.setClipToBounds(false);
864                             });  // nodeR
865         });                      // nodeC
866     });                          // nodeA
867     EXPECT_EQ(4, drawNode(renderThread, nodeA));
868 }
869 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderTwoReceivablesLikelyScenario)870 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesLikelyScenario) {
871     /* B and G are receivables, G is backward projected
872                 A
873                / \
874               B   C
875                  / \
876                 G   R
877     */
878     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
879                                                               SkiaRecordingCanvas& canvas) {
880         drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // B
881             props.setProjectionReceiver(true);
882         });  // nodeB
883         drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // C
884             drawOrderedNode(&canvas, 1,
885                             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // G
886                                 props.setProjectionReceiver(true);
887                                 props.setProjectBackwards(true);
888                                 props.setClipToBounds(false);
889                             });  // nodeG
890             drawOrderedNode(&canvas, 3,
891                             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // R
892                             });                                                         // nodeR
893         });                                                                             // nodeC
894     });                                                                                 // nodeA
895     EXPECT_EQ(4, drawNode(renderThread, nodeA));
896 }
897 
RENDERTHREAD_TEST(RenderNodeDrawable,projectionReorderTwoReceivablesDeeper)898 RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderTwoReceivablesDeeper) {
899     /* B and G are receivables, R is backward projected
900                 A
901                / \
902               B   C
903                  / \
904                 G   D
905                     |
906                     R
907     */
908     auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
909                                                               SkiaRecordingCanvas& canvas) {
910         drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // B
911             props.setProjectionReceiver(true);
912         });  // nodeB
913         drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // C
914             drawOrderedNode(&canvas, 2,
915                             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // G
916                                 props.setProjectionReceiver(true);
917                             });  // nodeG
918             drawOrderedNode(&canvas, 4,
919                             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {  // D
920                                 drawOrderedNode(&canvas, 3, [](RenderProperties& props,
921                                                                SkiaRecordingCanvas& canvas) {  // R
922                                     props.setProjectBackwards(true);
923                                     props.setClipToBounds(false);
924                                 });  // nodeR
925                             });      // nodeD
926         });                          // nodeC
927     });                              // nodeA
928     EXPECT_EQ(5, drawNode(renderThread, nodeA));
929 }
930 
RENDERTHREAD_TEST(RenderNodeDrawable,simple)931 RENDERTHREAD_TEST(RenderNodeDrawable, simple) {
932     static const int CANVAS_WIDTH = 100;
933     static const int CANVAS_HEIGHT = 200;
934     class SimpleTestCanvas : public TestCanvasBase {
935     public:
936         SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
937         void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
938             EXPECT_EQ(0, mDrawCounter++);
939         }
940         void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
941             EXPECT_EQ(1, mDrawCounter++);
942         }
943     };
944 
945     auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
946                                           [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
947                                               sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
948                                               canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
949                                                               SkPaint());
950                                               canvas.drawBitmap(*bitmap, 10, 10, nullptr);
951                                           });
952 
953     SimpleTestCanvas canvas;
954     RenderNodeDrawable drawable(node.get(), &canvas, true);
955     canvas.drawDrawable(&drawable);
956     EXPECT_EQ(2, canvas.mDrawCounter);
957 }
958 
RENDERTHREAD_TEST(RenderNodeDrawable,colorOp_unbounded)959 RENDERTHREAD_TEST(RenderNodeDrawable, colorOp_unbounded) {
960     static const int CANVAS_WIDTH = 200;
961     static const int CANVAS_HEIGHT = 200;
962     class ColorTestCanvas : public TestCanvasBase {
963     public:
964         ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
965         void onDrawPaint(const SkPaint&) {
966             switch (mDrawCounter++) {
967                 case 0:
968                     EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
969                               TestUtils::getClipBounds(this));
970                     break;
971                 case 1:
972                     EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
973                     break;
974                 default:
975                     ADD_FAILURE();
976             }
977         }
978     };
979 
980     auto unclippedColorView = TestUtils::createSkiaNode(
981             0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
982                 props.setClipToBounds(false);
983                 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
984             });
985 
986     auto clippedColorView = TestUtils::createSkiaNode(
987             0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
988                 canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
989             });
990 
991     ColorTestCanvas canvas;
992     RenderNodeDrawable drawable(unclippedColorView.get(), &canvas, true);
993     canvas.drawDrawable(&drawable);
994     EXPECT_EQ(1, canvas.mDrawCounter);
995     RenderNodeDrawable drawable2(clippedColorView.get(), &canvas, true);
996     canvas.drawDrawable(&drawable2);
997     EXPECT_EQ(2, canvas.mDrawCounter);
998 }
999 
TEST(RenderNodeDrawable,renderNode)1000 TEST(RenderNodeDrawable, renderNode) {
1001     static const int CANVAS_WIDTH = 200;
1002     static const int CANVAS_HEIGHT = 200;
1003     class RenderNodeTestCanvas : public TestCanvasBase {
1004     public:
1005         RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
1006         void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
1007             switch (mDrawCounter++) {
1008                 case 0:
1009                     EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
1010                               TestUtils::getClipBounds(this));
1011                     EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
1012                     break;
1013                 case 1:
1014                     EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
1015                     EXPECT_EQ(SK_ColorWHITE, paint.getColor());
1016                     break;
1017                 default:
1018                     ADD_FAILURE();
1019             }
1020         }
1021     };
1022 
1023     auto child = TestUtils::createSkiaNode(
1024             10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1025                 SkPaint paint;
1026                 paint.setColor(SK_ColorWHITE);
1027                 canvas.drawRect(0, 0, 100, 100, paint);
1028             });
1029 
1030     auto parent = TestUtils::createSkiaNode(
1031             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
1032             [&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1033                 SkPaint paint;
1034                 paint.setColor(SK_ColorDKGRAY);
1035                 canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
1036 
1037                 canvas.save(SaveFlags::MatrixClip);
1038                 canvas.translate(40, 40);
1039                 canvas.drawRenderNode(child.get());
1040                 canvas.restore();
1041             });
1042 
1043     RenderNodeTestCanvas canvas;
1044     RenderNodeDrawable drawable(parent.get(), &canvas, true);
1045     canvas.drawDrawable(&drawable);
1046     EXPECT_EQ(2, canvas.mDrawCounter);
1047 }
1048 
1049 // Verify that layers are composed with kLow_SkFilterQuality filter quality.
RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable,layerComposeQuality)1050 RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
1051     static const int CANVAS_WIDTH = 1;
1052     static const int CANVAS_HEIGHT = 1;
1053     static const int LAYER_WIDTH = 1;
1054     static const int LAYER_HEIGHT = 1;
1055     class FrameTestCanvas : public TestCanvasBase {
1056     public:
1057         FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
1058         void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
1059                              const SkPaint* paint, SrcRectConstraint constraint) override {
1060             mDrawCounter++;
1061             EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality());
1062         }
1063     };
1064 
1065     auto layerNode = TestUtils::createSkiaNode(
1066             0, 0, LAYER_WIDTH, LAYER_HEIGHT,
1067             [](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
1068                 canvas.drawPaint(SkPaint());
1069             });
1070 
1071     layerNode->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
1072     layerNode->setLayerSurface(SkSurface::MakeRasterN32Premul(LAYER_WIDTH, LAYER_HEIGHT));
1073 
1074     FrameTestCanvas canvas;
1075     RenderNodeDrawable drawable(layerNode.get(), &canvas, true);
1076     canvas.drawDrawable(&drawable);
1077     EXPECT_EQ(1, canvas.mDrawCounter);  // make sure the layer was composed
1078 
1079     // clean up layer pointer, so we can safely destruct RenderNode
1080     layerNode->setLayerSurface(nullptr);
1081 }
1082 
TEST(ReorderBarrierDrawable,testShadowMatrix)1083 TEST(ReorderBarrierDrawable, testShadowMatrix) {
1084     static const int CANVAS_WIDTH = 100;
1085     static const int CANVAS_HEIGHT = 100;
1086     static const float TRANSLATE_X = 11.0f;
1087     static const float TRANSLATE_Y = 22.0f;
1088     static const float CASTER_X = 40.0f;
1089     static const float CASTER_Y = 40.0f;
1090     static const float CASTER_WIDTH = 20.0f;
1091     static const float CASTER_HEIGHT = 20.0f;
1092 
1093     class ShadowTestCanvas : public SkCanvas {
1094     public:
1095         ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
1096         int getDrawCounter() { return mDrawCounter; }
1097 
1098         virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
1099             // expect to draw 2 RenderNodeDrawable, 1 StartReorderBarrierDrawable,
1100             // 1 EndReorderBarrierDrawable
1101             mDrawCounter++;
1102             SkCanvas::onDrawDrawable(drawable, matrix);
1103         }
1104 
1105         virtual void didTranslate(SkScalar dx, SkScalar dy) override {
1106             mDrawCounter++;
1107             EXPECT_EQ(dx, TRANSLATE_X);
1108             EXPECT_EQ(dy, TRANSLATE_Y);
1109         }
1110 
1111         virtual void didSetMatrix(const SkMatrix& matrix) override {
1112             mDrawCounter++;
1113             // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
1114             // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
1115             EXPECT_TRUE(matrix.isIdentity());
1116             EXPECT_TRUE(getTotalMatrix().isIdentity());
1117         }
1118 
1119         virtual void didConcat(const SkMatrix& matrix) override {
1120             mDrawCounter++;
1121             if (mFirstDidConcat) {
1122                 // First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
1123                 mFirstDidConcat = false;
1124                 EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
1125                           matrix);
1126                 EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
1127                           getTotalMatrix());
1128             } else {
1129                 // Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
1130                 EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), matrix);
1131                 EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y), getTotalMatrix());
1132             }
1133         }
1134 
1135     protected:
1136         int mDrawCounter = 0;
1137 
1138     private:
1139         bool mFirstDidConcat = true;
1140     };
1141 
1142     auto parent = TestUtils::createSkiaNode(
1143             0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
1144             [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1145                 canvas.translate(TRANSLATE_X, TRANSLATE_Y);
1146                 canvas.insertReorderBarrier(true);
1147 
1148                 auto node = TestUtils::createSkiaNode(
1149                         CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT,
1150                         [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1151                             props.setElevation(42);
1152                             props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
1153                             props.mutableOutline().setShouldClip(true);
1154                         });
1155                 canvas.drawRenderNode(node.get());
1156                 canvas.insertReorderBarrier(false);
1157             });
1158 
1159     // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
1160     ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
1161     RenderNodeDrawable drawable(parent.get(), &canvas, false);
1162     canvas.drawDrawable(&drawable);
1163     EXPECT_EQ(9, canvas.getDrawCounter());
1164 }
1165 
1166 // Draw a vector drawable twice but with different bounds and verify correct bounds are used.
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas,drawVectorDrawable)1167 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaRecordingCanvas, drawVectorDrawable) {
1168     static const int CANVAS_WIDTH = 100;
1169     static const int CANVAS_HEIGHT = 200;
1170     class VectorDrawableTestCanvas : public TestCanvasBase {
1171     public:
1172         VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
1173         void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
1174                               const SkPaint* paint, SrcRectConstraint constraint) override {
1175             const int index = mDrawCounter++;
1176             switch (index) {
1177                 case 0:
1178                     EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
1179                     break;
1180                 case 1:
1181                     EXPECT_EQ(dst, SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
1182                     break;
1183                 default:
1184                     ADD_FAILURE();
1185             }
1186         }
1187     };
1188 
1189     VectorDrawable::Group* group = new VectorDrawable::Group();
1190     sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
1191     vectorDrawable->mutateStagingProperties()->setScaledSize(CANVAS_WIDTH / 10, CANVAS_HEIGHT / 10);
1192 
1193     auto node =
1194             TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
1195                                       [&](RenderProperties& props, SkiaRecordingCanvas& canvas) {
1196                                           vectorDrawable->mutateStagingProperties()->setBounds(
1197                                                   SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT));
1198                                           canvas.drawVectorDrawable(vectorDrawable.get());
1199                                           vectorDrawable->mutateStagingProperties()->setBounds(
1200                                                   SkRect::MakeWH(CANVAS_WIDTH / 2, CANVAS_HEIGHT));
1201                                           canvas.drawVectorDrawable(vectorDrawable.get());
1202                                       });
1203 
1204     VectorDrawableTestCanvas canvas;
1205     RenderNodeDrawable drawable(node.get(), &canvas, true);
1206     canvas.drawDrawable(&drawable);
1207     EXPECT_EQ(2, canvas.mDrawCounter);
1208 }
1209