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