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