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