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