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 <gtest/gtest.h>
     18 
     19 #include <BakedOpState.h>
     20 #include <DeferredLayerUpdater.h>
     21 #include <FrameBuilder.h>
     22 #include <LayerUpdateQueue.h>
     23 #include <RecordedOp.h>
     24 #include <RecordingCanvas.h>
     25 #include <tests/common/TestUtils.h>
     26 
     27 #include <unordered_map>
     28 
     29 namespace android {
     30 namespace uirenderer {
     31 
     32 const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
     33 
     34 /**
     35  * Virtual class implemented by each test to redirect static operation / state transitions to
     36  * virtual methods.
     37  *
     38  * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
     39  * and allows Renderer vs Dispatching behavior to be merged.
     40  *
     41  * onXXXOp methods fail by default - tests should override ops they expect
     42  * startRepaintLayer fails by default - tests should override if expected
     43  * startFrame/endFrame do nothing by default - tests should override to intercept
     44  */
     45 class TestRendererBase {
     46 public:
     47     virtual ~TestRendererBase() {}
     48     virtual OffscreenBuffer* startTemporaryLayer(uint32_t, uint32_t) {
     49         ADD_FAILURE() << "Temporary layers not expected in this test";
     50         return nullptr;
     51     }
     52     virtual void recycleTemporaryLayer(OffscreenBuffer*) {
     53         ADD_FAILURE() << "Temporary layers not expected in this test";
     54     }
     55     virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
     56         ADD_FAILURE() << "Layer repaint not expected in this test";
     57     }
     58     virtual void endLayer() {
     59         ADD_FAILURE() << "Layer updates not expected in this test";
     60     }
     61     virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
     62     virtual void endFrame(const Rect& repaintRect) {}
     63 
     64     // define virtual defaults for single draw methods
     65 #define X(Type) \
     66     virtual void on##Type(const Type&, const BakedOpState&) { \
     67         ADD_FAILURE() << #Type " not expected in this test"; \
     68     }
     69     MAP_RENDERABLE_OPS(X)
     70 #undef X
     71 
     72     // define virtual defaults for merged draw methods
     73 #define X(Type) \
     74     virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
     75         ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
     76     }
     77     MAP_MERGEABLE_OPS(X)
     78 #undef X
     79 
     80     int getIndex() { return mIndex; }
     81 
     82 protected:
     83     int mIndex = 0;
     84 };
     85 
     86 /**
     87  * Dispatches all static methods to similar formed methods on renderer, which fail by default but
     88  * are overridden by subclasses per test.
     89  */
     90 class TestDispatcher {
     91 public:
     92     // define single op methods, which redirect to TestRendererBase
     93 #define X(Type) \
     94     static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
     95         renderer.on##Type(op, state); \
     96     }
     97     MAP_RENDERABLE_OPS(X);
     98 #undef X
     99 
    100     // define merged op methods, which redirect to TestRendererBase
    101 #define X(Type) \
    102     static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
    103         renderer.onMerged##Type##s(opList); \
    104     }
    105     MAP_MERGEABLE_OPS(X);
    106 #undef X
    107 };
    108 
    109 class FailRenderer : public TestRendererBase {};
    110 
    111 RENDERTHREAD_TEST(FrameBuilder, simple) {
    112     class SimpleTestRenderer : public TestRendererBase {
    113     public:
    114         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
    115             EXPECT_EQ(0, mIndex++);
    116             EXPECT_EQ(100u, width);
    117             EXPECT_EQ(200u, height);
    118         }
    119         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    120             EXPECT_EQ(1, mIndex++);
    121         }
    122         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
    123             EXPECT_EQ(2, mIndex++);
    124         }
    125         void endFrame(const Rect& repaintRect) override {
    126             EXPECT_EQ(3, mIndex++);
    127         }
    128     };
    129 
    130     auto node = TestUtils::createNode(0, 0, 100, 200,
    131             [](RenderProperties& props, RecordingCanvas& canvas) {
    132         SkBitmap bitmap = TestUtils::createSkBitmap(25, 25);
    133         canvas.drawRect(0, 0, 100, 200, SkPaint());
    134         canvas.drawBitmap(bitmap, 10, 10, nullptr);
    135     });
    136     FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
    137             sLightGeometry, Caches::getInstance());
    138     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    139 
    140     SimpleTestRenderer renderer;
    141     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    142     EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
    143 }
    144 
    145 RENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
    146     class SimpleStrokeTestRenderer : public TestRendererBase {
    147     public:
    148         void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
    149             EXPECT_EQ(0, mIndex++);
    150             // even though initial bounds are empty...
    151             EXPECT_TRUE(op.unmappedBounds.isEmpty())
    152                     << "initial bounds should be empty, since they're unstroked";
    153             EXPECT_EQ(Rect(45, 45, 55, 55), state.computedState.clippedBounds)
    154                     << "final bounds should account for stroke";
    155         }
    156     };
    157 
    158     auto node = TestUtils::createNode(0, 0, 100, 200,
    159             [](RenderProperties& props, RecordingCanvas& canvas) {
    160         SkPaint strokedPaint;
    161         strokedPaint.setStrokeWidth(10);
    162         canvas.drawPoint(50, 50, strokedPaint);
    163     });
    164     FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
    165             sLightGeometry, Caches::getInstance());
    166     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    167 
    168     SimpleStrokeTestRenderer renderer;
    169     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    170     EXPECT_EQ(1, renderer.getIndex());
    171 }
    172 
    173 RENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
    174     auto node = TestUtils::createNode(0, 0, 200, 200,
    175             [](RenderProperties& props, RecordingCanvas& canvas) {
    176         canvas.save(SaveFlags::MatrixClip);
    177         canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op); // intersection should be empty
    178         canvas.drawRect(0, 0, 400, 400, SkPaint());
    179         canvas.restore();
    180     });
    181     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    182             sLightGeometry, Caches::getInstance());
    183     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    184 
    185     FailRenderer renderer;
    186     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    187 }
    188 
    189 RENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
    190     const int LOOPS = 5;
    191     class SimpleBatchingTestRenderer : public TestRendererBase {
    192     public:
    193         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
    194             EXPECT_TRUE(mIndex++ >= LOOPS) << "Bitmaps should be above all rects";
    195         }
    196         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    197             EXPECT_TRUE(mIndex++ < LOOPS) << "Rects should be below all bitmaps";
    198         }
    199     };
    200 
    201     auto node = TestUtils::createNode(0, 0, 200, 200,
    202             [](RenderProperties& props, RecordingCanvas& canvas) {
    203         SkBitmap bitmap = TestUtils::createSkBitmap(10, 10,
    204                 kAlpha_8_SkColorType); // Disable merging by using alpha 8 bitmap
    205 
    206         // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
    207         // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
    208         canvas.save(SaveFlags::MatrixClip);
    209         for (int i = 0; i < LOOPS; i++) {
    210             canvas.translate(0, 10);
    211             canvas.drawRect(0, 0, 10, 10, SkPaint());
    212             canvas.drawBitmap(bitmap, 5, 0, nullptr);
    213         }
    214         canvas.restore();
    215     });
    216     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    217             sLightGeometry, Caches::getInstance());
    218     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    219 
    220     SimpleBatchingTestRenderer renderer;
    221     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    222     EXPECT_EQ(2 * LOOPS, renderer.getIndex())
    223             << "Expect number of ops = 2 * loop count";
    224 }
    225 
    226 RENDERTHREAD_TEST(FrameBuilder, deferRenderNode_translateClip) {
    227     class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase {
    228     public:
    229         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    230             EXPECT_EQ(0, mIndex++);
    231             EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds);
    232             EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom,
    233                     state.computedState.clipSideFlags);
    234         }
    235     };
    236 
    237     auto node = TestUtils::createNode(0, 0, 100, 100,
    238             [](RenderProperties& props, RecordingCanvas& canvas) {
    239         canvas.drawRect(0, 0, 100, 100, SkPaint());
    240     });
    241 
    242     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
    243             sLightGeometry, Caches::getInstance());
    244     frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
    245             *TestUtils::getSyncedNode(node));
    246 
    247     DeferRenderNodeTranslateClipTestRenderer renderer;
    248     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    249     EXPECT_EQ(1, renderer.getIndex());
    250 }
    251 
    252 RENDERTHREAD_TEST(FrameBuilder, deferRenderNodeScene) {
    253     class DeferRenderNodeSceneTestRenderer : public TestRendererBase {
    254     public:
    255         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    256             const Rect& clippedBounds = state.computedState.clippedBounds;
    257             Matrix4 expected;
    258             switch (mIndex++) {
    259             case 0:
    260                 // background - left side
    261                 EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
    262                 expected.loadTranslate(100, 100, 0);
    263                 break;
    264             case 1:
    265                 // background - top side
    266                 EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
    267                 expected.loadTranslate(100, 100, 0);
    268                 break;
    269             case 2:
    270                 // content
    271                 EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
    272                 expected.loadTranslate(-50, -50, 0);
    273                 break;
    274             case 3:
    275                 // overlay
    276                 EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
    277                 break;
    278             default:
    279                 ADD_FAILURE() << "Too many rects observed";
    280             }
    281             EXPECT_EQ(expected, state.computedState.transform);
    282         }
    283     };
    284 
    285     std::vector<sp<RenderNode>> nodes;
    286     SkPaint transparentPaint;
    287     transparentPaint.setAlpha(128);
    288 
    289     // backdrop
    290     nodes.push_back(TestUtils::createNode(100, 100, 700, 500, // 600x400
    291             [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
    292         canvas.drawRect(0, 0, 600, 400, transparentPaint);
    293     }));
    294 
    295     // content
    296     Rect contentDrawBounds(150, 150, 650, 450); // 500x300
    297     nodes.push_back(TestUtils::createNode(0, 0, 800, 600,
    298             [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
    299         canvas.drawRect(0, 0, 800, 600, transparentPaint);
    300     }));
    301 
    302     // overlay
    303     nodes.push_back(TestUtils::createNode(0, 0, 800, 600,
    304             [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
    305         canvas.drawRect(0, 0, 800, 200, transparentPaint);
    306     }));
    307 
    308     for (auto& node : nodes) {
    309         TestUtils::syncHierarchyPropertiesAndDisplayList(node);
    310     }
    311 
    312     FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
    313             sLightGeometry, Caches::getInstance());
    314     frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
    315 
    316     DeferRenderNodeSceneTestRenderer renderer;
    317     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    318     EXPECT_EQ(4, renderer.getIndex());
    319 }
    320 
    321 RENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
    322     class EmptyNoFbo0TestRenderer : public TestRendererBase {
    323     public:
    324         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
    325             ADD_FAILURE() << "Primary frame draw not expected in this test";
    326         }
    327         void endFrame(const Rect& repaintRect) override {
    328             ADD_FAILURE() << "Primary frame draw not expected in this test";
    329         }
    330     };
    331 
    332     // Use layer update constructor, so no work is enqueued for Fbo0
    333     LayerUpdateQueue emptyLayerUpdateQueue;
    334     FrameBuilder frameBuilder(emptyLayerUpdateQueue, sLightGeometry, Caches::getInstance());
    335     EmptyNoFbo0TestRenderer renderer;
    336     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    337 }
    338 
    339 RENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
    340     class EmptyWithFbo0TestRenderer : public TestRendererBase {
    341     public:
    342         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
    343             EXPECT_EQ(0, mIndex++);
    344         }
    345         void endFrame(const Rect& repaintRect) override {
    346             EXPECT_EQ(1, mIndex++);
    347         }
    348     };
    349     auto node = TestUtils::createNode(10, 10, 110, 110,
    350             [](RenderProperties& props, RecordingCanvas& canvas) {
    351         // no drawn content
    352     });
    353 
    354     // Draw, but pass node without draw content, so no work is done for primary frame
    355     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    356             sLightGeometry, Caches::getInstance());
    357     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    358 
    359     EmptyWithFbo0TestRenderer renderer;
    360     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    361     EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
    362             " but fbo0 update lifecycle should still be observed";
    363 }
    364 
    365 RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
    366     class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
    367     public:
    368         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    369             EXPECT_EQ(mIndex++, 0) << "Should be one rect";
    370             EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds)
    371                     << "Last rect should occlude others.";
    372         }
    373     };
    374     auto node = TestUtils::createNode(0, 0, 200, 200,
    375             [](RenderProperties& props, RecordingCanvas& canvas) {
    376         canvas.drawRect(0, 0, 200, 200, SkPaint());
    377         canvas.drawRect(0, 0, 200, 200, SkPaint());
    378         canvas.drawRect(10, 10, 190, 190, SkPaint());
    379     });
    380 
    381     // Damage (and therefore clip) is same as last draw, subset of renderable area.
    382     // This means last op occludes other contents, and they'll be rejected to avoid overdraw.
    383     FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200,
    384             sLightGeometry, Caches::getInstance());
    385     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    386 
    387     EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
    388             << "Recording must not have rejected ops, in order for this test to be valid";
    389 
    390     AvoidOverdrawRectsTestRenderer renderer;
    391     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    392     EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
    393 }
    394 
    395 RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
    396     static SkBitmap opaqueBitmap = TestUtils::createSkBitmap(50, 50,
    397             SkColorType::kRGB_565_SkColorType);
    398     static SkBitmap transpBitmap = TestUtils::createSkBitmap(50, 50,
    399             SkColorType::kAlpha_8_SkColorType);
    400     class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
    401     public:
    402         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
    403             switch(mIndex++) {
    404             case 0:
    405                 EXPECT_EQ(opaqueBitmap.pixelRef(), op.bitmap->pixelRef());
    406                 break;
    407             case 1:
    408                 EXPECT_EQ(transpBitmap.pixelRef(), op.bitmap->pixelRef());
    409                 break;
    410             default:
    411                 ADD_FAILURE() << "Only two ops expected.";
    412             }
    413         }
    414     };
    415 
    416     auto node = TestUtils::createNode(0, 0, 50, 50,
    417             [](RenderProperties& props, RecordingCanvas& canvas) {
    418         canvas.drawRect(0, 0, 50, 50, SkPaint());
    419         canvas.drawRect(0, 0, 50, 50, SkPaint());
    420         canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
    421 
    422         // only the below draws should remain, since they're
    423         canvas.drawBitmap(opaqueBitmap, 0, 0, nullptr);
    424         canvas.drawBitmap(transpBitmap, 0, 0, nullptr);
    425     });
    426     FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50,
    427             sLightGeometry, Caches::getInstance());
    428     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    429 
    430     EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
    431             << "Recording must not have rejected ops, in order for this test to be valid";
    432 
    433     AvoidOverdrawBitmapsTestRenderer renderer;
    434     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    435     EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
    436 }
    437 
    438 RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
    439     class ClippedMergingTestRenderer : public TestRendererBase {
    440     public:
    441         void onMergedBitmapOps(const MergedBakedOpList& opList) override {
    442             EXPECT_EQ(0, mIndex);
    443             mIndex += opList.count;
    444             EXPECT_EQ(4u, opList.count);
    445             EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
    446             EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
    447                     opList.clipSideFlags);
    448         }
    449     };
    450     auto node = TestUtils::createNode(0, 0, 100, 100,
    451             [](RenderProperties& props, TestCanvas& canvas) {
    452         SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
    453 
    454         // left side clipped (to inset left half)
    455         canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
    456         canvas.drawBitmap(bitmap, 0, 40, nullptr);
    457 
    458         // top side clipped (to inset top half)
    459         canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
    460         canvas.drawBitmap(bitmap, 40, 0, nullptr);
    461 
    462         // right side clipped (to inset right half)
    463         canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
    464         canvas.drawBitmap(bitmap, 80, 40, nullptr);
    465 
    466         // bottom not clipped, just abutting (inset bottom half)
    467         canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
    468         canvas.drawBitmap(bitmap, 40, 70, nullptr);
    469     });
    470 
    471     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
    472             sLightGeometry, Caches::getInstance());
    473     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    474 
    475     ClippedMergingTestRenderer renderer;
    476     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    477     EXPECT_EQ(4, renderer.getIndex());
    478 }
    479 
    480 RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
    481     class RegionClipStopsMergeTestRenderer : public TestRendererBase {
    482     public:
    483         void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
    484     };
    485     auto node = TestUtils::createNode(0, 0, 400, 400,
    486             [](RenderProperties& props, TestCanvas& canvas) {
    487         SkPath path;
    488         path.addCircle(200, 200, 200, SkPath::kCW_Direction);
    489         canvas.save(SaveFlags::MatrixClip);
    490         canvas.clipPath(&path, SkRegion::kIntersect_Op);
    491         SkPaint paint;
    492         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    493         paint.setAntiAlias(true);
    494         paint.setTextSize(50);
    495         TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
    496         TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
    497         canvas.restore();
    498     });
    499 
    500     FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
    501             sLightGeometry, Caches::getInstance());
    502     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    503 
    504     RegionClipStopsMergeTestRenderer renderer;
    505     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    506     EXPECT_EQ(2, renderer.getIndex());
    507 }
    508 
    509 RENDERTHREAD_TEST(FrameBuilder, textMerging) {
    510     class TextMergingTestRenderer : public TestRendererBase {
    511     public:
    512         void onMergedTextOps(const MergedBakedOpList& opList) override {
    513             EXPECT_EQ(0, mIndex);
    514             mIndex += opList.count;
    515             EXPECT_EQ(2u, opList.count);
    516             EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
    517             EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
    518             EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
    519         }
    520     };
    521     auto node = TestUtils::createNode(0, 0, 400, 400,
    522             [](RenderProperties& props, TestCanvas& canvas) {
    523         SkPaint paint;
    524         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    525         paint.setAntiAlias(true);
    526         paint.setTextSize(50);
    527         TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
    528         TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
    529     });
    530     FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
    531             sLightGeometry, Caches::getInstance());
    532     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    533 
    534     TextMergingTestRenderer renderer;
    535     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    536     EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
    537 }
    538 
    539 RENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
    540     const int LOOPS = 5;
    541     class TextStrikethroughTestRenderer : public TestRendererBase {
    542     public:
    543         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    544             EXPECT_TRUE(mIndex++ >= LOOPS) << "Strikethrough rects should be above all text";
    545         }
    546         void onMergedTextOps(const MergedBakedOpList& opList) override {
    547             EXPECT_EQ(0, mIndex);
    548             mIndex += opList.count;
    549             EXPECT_EQ(5u, opList.count);
    550         }
    551     };
    552     auto node = TestUtils::createNode(0, 0, 200, 2000,
    553             [](RenderProperties& props, RecordingCanvas& canvas) {
    554         SkPaint textPaint;
    555         textPaint.setAntiAlias(true);
    556         textPaint.setTextSize(20);
    557         textPaint.setStrikeThruText(true);
    558         textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    559         for (int i = 0; i < LOOPS; i++) {
    560             TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
    561         }
    562     });
    563 
    564     FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000,
    565             sLightGeometry, Caches::getInstance());
    566     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    567 
    568     TextStrikethroughTestRenderer renderer;
    569     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    570     EXPECT_EQ(2 * LOOPS, renderer.getIndex())
    571             << "Expect number of ops = 2 * loop count";
    572 }
    573 
    574 static auto styles = {
    575         SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
    576 
    577 RENDERTHREAD_TEST(FrameBuilder, textStyle) {
    578     class TextStyleTestRenderer : public TestRendererBase {
    579     public:
    580         void onMergedTextOps(const MergedBakedOpList& opList) override {
    581             ASSERT_EQ(0, mIndex);
    582             ASSERT_EQ(3u, opList.count);
    583             mIndex += opList.count;
    584 
    585             int index = 0;
    586             for (auto style : styles) {
    587                 auto state = opList.states[index++];
    588                 ASSERT_EQ(style, state->op->paint->getStyle())
    589                         << "Remainder of validation relies upon stable merged order";
    590                 ASSERT_EQ(0, state->computedState.clipSideFlags)
    591                         << "Clipped bounds validation requires unclipped ops";
    592             }
    593 
    594             Rect fill = opList.states[0]->computedState.clippedBounds;
    595             Rect stroke = opList.states[1]->computedState.clippedBounds;
    596             EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
    597                     << "Stroke+Fill should be same as stroke";
    598 
    599             EXPECT_TRUE(stroke.contains(fill));
    600             EXPECT_FALSE(fill.contains(stroke));
    601 
    602             // outset by half the stroke width
    603             Rect outsetFill(fill);
    604             outsetFill.outset(5);
    605             EXPECT_EQ(stroke, outsetFill);
    606         }
    607     };
    608     auto node = TestUtils::createNode(0, 0, 400, 400,
    609             [](RenderProperties& props, TestCanvas& canvas) {
    610         SkPaint paint;
    611         paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    612         paint.setAntiAlias(true);
    613         paint.setTextSize(50);
    614         paint.setStrokeWidth(10);
    615 
    616         // draw 3 copies of the same text overlapping, each with a different style.
    617         // They'll get merged, but with
    618         for (auto style : styles) {
    619             paint.setStyle(style);
    620             TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
    621         }
    622     });
    623     FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
    624             sLightGeometry, Caches::getInstance());
    625     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    626     TextStyleTestRenderer renderer;
    627     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    628     EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
    629 }
    630 
    631 RENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
    632     class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
    633     public:
    634         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
    635             EXPECT_EQ(0, mIndex++);
    636             EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
    637             EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
    638 
    639             Matrix4 expected;
    640             expected.loadTranslate(5, 5, 0);
    641             EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
    642         }
    643     };
    644 
    645     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
    646             SkMatrix::MakeTrans(5, 5));
    647 
    648     auto node = TestUtils::createNode(0, 0, 200, 200,
    649             [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
    650         canvas.save(SaveFlags::MatrixClip);
    651         canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
    652         canvas.drawLayer(layerUpdater.get());
    653         canvas.restore();
    654     });
    655 
    656     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    657             sLightGeometry, Caches::getInstance());
    658     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    659 
    660     TextureLayerClipLocalMatrixTestRenderer renderer;
    661     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    662     EXPECT_EQ(1, renderer.getIndex());
    663 }
    664 
    665 RENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
    666     class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
    667     public:
    668         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
    669             EXPECT_EQ(0, mIndex++);
    670 
    671             Matrix4 expected;
    672             expected.loadTranslate(35, 45, 0);
    673             EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
    674         }
    675     };
    676 
    677     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
    678             SkMatrix::MakeTrans(5, 5));
    679 
    680     auto node = TestUtils::createNode(0, 0, 200, 200,
    681             [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
    682         canvas.save(SaveFlags::MatrixClip);
    683         canvas.translate(30, 40);
    684         canvas.drawLayer(layerUpdater.get());
    685         canvas.restore();
    686     });
    687 
    688     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    689             sLightGeometry, Caches::getInstance());
    690     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    691 
    692     TextureLayerCombineMatricesTestRenderer renderer;
    693     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    694     EXPECT_EQ(1, renderer.getIndex());
    695 }
    696 
    697 RENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
    698     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
    699             SkMatrix::MakeTrans(5, 5));
    700     layerUpdater->backingLayer()->setRenderTarget(GL_NONE); // Should be rejected
    701 
    702     auto node = TestUtils::createNode(0, 0, 200, 200,
    703             [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
    704         canvas.drawLayer(layerUpdater.get());
    705     });
    706 
    707     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    708             sLightGeometry, Caches::getInstance());
    709     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    710 
    711     FailRenderer renderer;
    712     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    713 }
    714 
    715 RENDERTHREAD_TEST(FrameBuilder, functor_reject) {
    716     class FunctorTestRenderer : public TestRendererBase {
    717     public:
    718         void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
    719             EXPECT_EQ(0, mIndex++);
    720         }
    721     };
    722     Functor noopFunctor;
    723 
    724     // 1 million pixel tall view, scrolled down 80%
    725     auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000,
    726             [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
    727         canvas.translate(0, -800000);
    728         canvas.callDrawGLFunction(&noopFunctor, nullptr);
    729     });
    730 
    731     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    732             sLightGeometry, Caches::getInstance());
    733     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView));
    734 
    735     FunctorTestRenderer renderer;
    736     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    737     EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
    738 }
    739 
    740 RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
    741     class ColorTestRenderer : public TestRendererBase {
    742     public:
    743         void onColorOp(const ColorOp& op, const BakedOpState& state) override {
    744             EXPECT_EQ(0, mIndex++);
    745             EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
    746                     << "Color op should be expanded to bounds of surrounding";
    747         }
    748     };
    749 
    750     auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
    751             [](RenderProperties& props, RecordingCanvas& canvas) {
    752         props.setClipToBounds(false);
    753         canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
    754     });
    755 
    756     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    757             sLightGeometry, Caches::getInstance());
    758     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView));
    759 
    760     ColorTestRenderer renderer;
    761     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    762     EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
    763 }
    764 
    765 TEST(FrameBuilder, renderNode) {
    766     class RenderNodeTestRenderer : public TestRendererBase {
    767     public:
    768         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    769             switch(mIndex++) {
    770             case 0:
    771                 EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
    772                 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
    773                 break;
    774             case 1:
    775                 EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
    776                 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
    777                 break;
    778             default:
    779                 ADD_FAILURE();
    780             }
    781         }
    782     };
    783 
    784     auto child = TestUtils::createNode(10, 10, 110, 110,
    785             [](RenderProperties& props, RecordingCanvas& canvas) {
    786         SkPaint paint;
    787         paint.setColor(SK_ColorWHITE);
    788         canvas.drawRect(0, 0, 100, 100, paint);
    789     });
    790 
    791     auto parent = TestUtils::createNode(0, 0, 200, 200,
    792             [&child](RenderProperties& props, RecordingCanvas& canvas) {
    793         SkPaint paint;
    794         paint.setColor(SK_ColorDKGRAY);
    795         canvas.drawRect(0, 0, 200, 200, paint);
    796 
    797         canvas.save(SaveFlags::MatrixClip);
    798         canvas.translate(40, 40);
    799         canvas.drawRenderNode(child.get());
    800         canvas.restore();
    801     });
    802 
    803     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    804             sLightGeometry, Caches::getInstance());
    805     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
    806 
    807     RenderNodeTestRenderer renderer;
    808     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    809     EXPECT_EQ(2, renderer.getIndex());
    810 }
    811 
    812 RENDERTHREAD_TEST(FrameBuilder, clipped) {
    813     class ClippedTestRenderer : public TestRendererBase {
    814     public:
    815         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
    816             EXPECT_EQ(0, mIndex++);
    817             EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
    818             EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
    819             EXPECT_TRUE(state.computedState.transform.isIdentity());
    820         }
    821     };
    822 
    823     auto node = TestUtils::createNode(0, 0, 200, 200,
    824             [](RenderProperties& props, RecordingCanvas& canvas) {
    825         SkBitmap bitmap = TestUtils::createSkBitmap(200, 200);
    826         canvas.drawBitmap(bitmap, 0, 0, nullptr);
    827     });
    828 
    829     // clip to small area, should see in receiver
    830     FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200,
    831             sLightGeometry, Caches::getInstance());
    832     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    833 
    834     ClippedTestRenderer renderer;
    835     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    836 }
    837 
    838 RENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
    839     class SaveLayerSimpleTestRenderer : public TestRendererBase {
    840     public:
    841         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
    842             EXPECT_EQ(0, mIndex++);
    843             EXPECT_EQ(180u, width);
    844             EXPECT_EQ(180u, height);
    845             return nullptr;
    846         }
    847         void endLayer() override {
    848             EXPECT_EQ(2, mIndex++);
    849         }
    850         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    851             EXPECT_EQ(1, mIndex++);
    852             EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
    853             EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
    854             EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
    855 
    856             Matrix4 expectedTransform;
    857             expectedTransform.loadTranslate(-10, -10, 0);
    858             EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
    859         }
    860         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
    861             EXPECT_EQ(3, mIndex++);
    862             EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
    863             EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
    864             EXPECT_TRUE(state.computedState.transform.isIdentity());
    865         }
    866         void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
    867             EXPECT_EQ(4, mIndex++);
    868             EXPECT_EQ(nullptr, offscreenBuffer);
    869         }
    870     };
    871 
    872     auto node = TestUtils::createNode(0, 0, 200, 200,
    873             [](RenderProperties& props, RecordingCanvas& canvas) {
    874         canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
    875         canvas.drawRect(10, 10, 190, 190, SkPaint());
    876         canvas.restore();
    877     });
    878 
    879     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    880             sLightGeometry, Caches::getInstance());
    881     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    882 
    883     SaveLayerSimpleTestRenderer renderer;
    884     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    885     EXPECT_EQ(5, renderer.getIndex());
    886 }
    887 
    888 RENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
    889     /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
    890      * - startTemporaryLayer2, rect2 endLayer2
    891      * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
    892      * - startFrame, layerOp1, endFrame
    893      */
    894     class SaveLayerNestedTestRenderer : public TestRendererBase {
    895     public:
    896         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
    897             const int index = mIndex++;
    898             if (index == 0) {
    899                 EXPECT_EQ(400u, width);
    900                 EXPECT_EQ(400u, height);
    901                 return (OffscreenBuffer*) 0x400;
    902             } else if (index == 3) {
    903                 EXPECT_EQ(800u, width);
    904                 EXPECT_EQ(800u, height);
    905                 return (OffscreenBuffer*) 0x800;
    906             } else { ADD_FAILURE(); }
    907             return (OffscreenBuffer*) nullptr;
    908         }
    909         void endLayer() override {
    910             int index = mIndex++;
    911             EXPECT_TRUE(index == 2 || index == 6);
    912         }
    913         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
    914             EXPECT_EQ(7, mIndex++);
    915         }
    916         void endFrame(const Rect& repaintRect) override {
    917             EXPECT_EQ(9, mIndex++);
    918         }
    919         void onRectOp(const RectOp& op, const BakedOpState& state) override {
    920             const int index = mIndex++;
    921             if (index == 1) {
    922                 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
    923             } else if (index == 4) {
    924                 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
    925             } else { ADD_FAILURE(); }
    926         }
    927         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
    928             const int index = mIndex++;
    929             if (index == 5) {
    930                 EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
    931                 EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
    932             } else if (index == 8) {
    933                 EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
    934                 EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
    935             } else { ADD_FAILURE(); }
    936         }
    937         void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
    938             const int index = mIndex++;
    939             // order isn't important, but we need to see both
    940             if (index == 10) {
    941                 EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
    942             } else if (index == 11) {
    943                 EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
    944             } else { ADD_FAILURE(); }
    945         }
    946     };
    947 
    948     auto node = TestUtils::createNode(0, 0, 800, 800,
    949             [](RenderProperties& props, RecordingCanvas& canvas) {
    950         canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
    951         {
    952             canvas.drawRect(0, 0, 800, 800, SkPaint());
    953             canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
    954             {
    955                 canvas.drawRect(0, 0, 400, 400, SkPaint());
    956             }
    957             canvas.restore();
    958         }
    959         canvas.restore();
    960     });
    961 
    962     FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800,
    963             sLightGeometry, Caches::getInstance());
    964     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    965 
    966     SaveLayerNestedTestRenderer renderer;
    967     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    968     EXPECT_EQ(12, renderer.getIndex());
    969 }
    970 
    971 RENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
    972         auto node = TestUtils::createNode(0, 0, 200, 200,
    973                 [](RenderProperties& props, RecordingCanvas& canvas) {
    974         canvas.save(SaveFlags::MatrixClip);
    975         canvas.clipRect(200, 200, 400, 400, SkRegion::kIntersect_Op);
    976         canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
    977 
    978         // draw within save layer may still be recorded, but shouldn't be drawn
    979         canvas.drawRect(200, 200, 400, 400, SkPaint());
    980 
    981         canvas.restore();
    982         canvas.restore();
    983     });
    984 
    985     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
    986             sLightGeometry, Caches::getInstance());
    987     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
    988 
    989     FailRenderer renderer;
    990     // should see no ops, even within the layer, since the layer should be rejected
    991     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
    992 }
    993 
    994 RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
    995     class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
    996     public:
    997         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
    998             EXPECT_EQ(0, mIndex++);
    999             EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
   1000             EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
   1001             EXPECT_TRUE(state.computedState.transform.isIdentity());
   1002         }
   1003         void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
   1004             EXPECT_EQ(1, mIndex++);
   1005             ASSERT_NE(nullptr, op.paint);
   1006             ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
   1007         }
   1008         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1009             EXPECT_EQ(2, mIndex++);
   1010             EXPECT_EQ(Rect(200, 200), op.unmappedBounds);
   1011             EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
   1012             EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
   1013             EXPECT_TRUE(state.computedState.transform.isIdentity());
   1014         }
   1015         void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
   1016             EXPECT_EQ(3, mIndex++);
   1017             EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
   1018             EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState);
   1019             EXPECT_TRUE(state.computedState.transform.isIdentity());
   1020         }
   1021     };
   1022 
   1023     auto node = TestUtils::createNode(0, 0, 200, 200,
   1024             [](RenderProperties& props, RecordingCanvas& canvas) {
   1025         canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
   1026         canvas.drawRect(0, 0, 200, 200, SkPaint());
   1027         canvas.restore();
   1028     });
   1029 
   1030     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1031             sLightGeometry, Caches::getInstance());
   1032     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   1033 
   1034     SaveLayerUnclippedSimpleTestRenderer renderer;
   1035     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1036     EXPECT_EQ(4, renderer.getIndex());
   1037 }
   1038 
   1039 RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_round) {
   1040     class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase {
   1041     public:
   1042         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
   1043             EXPECT_EQ(0, mIndex++);
   1044             EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
   1045                     << "Bounds rect should round out";
   1046         }
   1047         void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {}
   1048         void onRectOp(const RectOp& op, const BakedOpState& state) override {}
   1049         void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
   1050             EXPECT_EQ(1, mIndex++);
   1051             EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds)
   1052                     << "Bounds rect should round out";
   1053         }
   1054     };
   1055 
   1056     auto node = TestUtils::createNode(0, 0, 200, 200,
   1057             [](RenderProperties& props, RecordingCanvas& canvas) {
   1058         canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
   1059                 128, (SaveFlags::Flags)(0));
   1060         canvas.drawRect(0, 0, 200, 200, SkPaint());
   1061         canvas.restore();
   1062     });
   1063 
   1064     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1065             sLightGeometry, Caches::getInstance());
   1066     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   1067 
   1068     SaveLayerUnclippedRoundTestRenderer renderer;
   1069     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1070     EXPECT_EQ(2, renderer.getIndex());
   1071 }
   1072 
   1073 RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
   1074     class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
   1075     public:
   1076         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
   1077             int index = mIndex++;
   1078             EXPECT_GT(4, index);
   1079             EXPECT_EQ(5, op.unmappedBounds.getWidth());
   1080             EXPECT_EQ(5, op.unmappedBounds.getHeight());
   1081             if (index == 0) {
   1082                 EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds);
   1083             } else if (index == 1) {
   1084                 EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds);
   1085             } else if (index == 2) {
   1086                 EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds);
   1087             } else if (index == 3) {
   1088                 EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds);
   1089             }
   1090         }
   1091         void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
   1092             EXPECT_EQ(4, mIndex++);
   1093             ASSERT_EQ(op.vertexCount, 16u);
   1094             for (size_t i = 0; i < op.vertexCount; i++) {
   1095                 auto v = op.vertices[i];
   1096                 EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200);
   1097                 EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200);
   1098             }
   1099         }
   1100         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1101             EXPECT_EQ(5, mIndex++);
   1102         }
   1103         void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
   1104             EXPECT_LT(5, mIndex++);
   1105         }
   1106     };
   1107 
   1108     auto node = TestUtils::createNode(0, 0, 200, 200,
   1109             [](RenderProperties& props, RecordingCanvas& canvas) {
   1110 
   1111         int restoreTo = canvas.save(SaveFlags::MatrixClip);
   1112         canvas.scale(2, 2);
   1113         canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
   1114         canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
   1115         canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
   1116         canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
   1117         canvas.drawRect(0, 0, 100, 100, SkPaint());
   1118         canvas.restoreToCount(restoreTo);
   1119     });
   1120 
   1121     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1122             sLightGeometry, Caches::getInstance());
   1123     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   1124 
   1125     SaveLayerUnclippedMergedClearsTestRenderer renderer;
   1126     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1127     EXPECT_EQ(10, renderer.getIndex())
   1128             << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
   1129 }
   1130 
   1131 RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
   1132     class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
   1133     public:
   1134         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
   1135             EXPECT_EQ(0, mIndex++);
   1136         }
   1137         void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
   1138             EXPECT_EQ(1, mIndex++);
   1139             ASSERT_NE(nullptr, op.paint);
   1140             EXPECT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint));
   1141             EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds)
   1142                     << "Expect dirty rect as clip";
   1143             ASSERT_NE(nullptr, state.computedState.clipState);
   1144             EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipState->rect);
   1145             EXPECT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
   1146         }
   1147         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1148             EXPECT_EQ(2, mIndex++);
   1149         }
   1150         void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
   1151             EXPECT_EQ(3, mIndex++);
   1152         }
   1153     };
   1154 
   1155     auto node = TestUtils::createNode(0, 0, 200, 200,
   1156             [](RenderProperties& props, RecordingCanvas& canvas) {
   1157         // save smaller than clip, so we get unclipped behavior
   1158         canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
   1159         canvas.drawRect(0, 0, 200, 200, SkPaint());
   1160         canvas.restore();
   1161     });
   1162 
   1163     // draw with partial screen dirty, and assert we see that rect later
   1164     FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
   1165             sLightGeometry, Caches::getInstance());
   1166     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   1167 
   1168     SaveLayerUnclippedClearClipTestRenderer renderer;
   1169     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1170     EXPECT_EQ(4, renderer.getIndex());
   1171 }
   1172 
   1173 RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
   1174     auto node = TestUtils::createNode(0, 0, 200, 200,
   1175             [](RenderProperties& props, RecordingCanvas& canvas) {
   1176         // unclipped savelayer + rect both in area that won't intersect with dirty
   1177         canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
   1178         canvas.drawRect(100, 100, 200, 200, SkPaint());
   1179         canvas.restore();
   1180     });
   1181 
   1182     // draw with partial screen dirty that doesn't intersect with savelayer
   1183     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
   1184             sLightGeometry, Caches::getInstance());
   1185     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   1186 
   1187     FailRenderer renderer;
   1188     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1189 }
   1190 
   1191 /* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as:
   1192  * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
   1193  * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
   1194  */
   1195 RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
   1196     class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
   1197     public:
   1198         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
   1199             EXPECT_EQ(0, mIndex++); // savelayer first
   1200             return (OffscreenBuffer*)0xabcd;
   1201         }
   1202         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
   1203             int index = mIndex++;
   1204             EXPECT_TRUE(index == 1 || index == 7);
   1205         }
   1206         void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override {
   1207             int index = mIndex++;
   1208             EXPECT_TRUE(index == 2 || index == 8);
   1209         }
   1210         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1211             EXPECT_EQ(3, mIndex++);
   1212             Matrix4 expected;
   1213             expected.loadTranslate(-100, -100, 0);
   1214             EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds);
   1215             EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
   1216         }
   1217         void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override {
   1218             int index = mIndex++;
   1219             EXPECT_TRUE(index == 4 || index == 10);
   1220         }
   1221         void endLayer() override {
   1222             EXPECT_EQ(5, mIndex++);
   1223         }
   1224         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
   1225             EXPECT_EQ(6, mIndex++);
   1226         }
   1227         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
   1228             EXPECT_EQ(9, mIndex++);
   1229             EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
   1230         }
   1231         void endFrame(const Rect& repaintRect) override {
   1232             EXPECT_EQ(11, mIndex++);
   1233         }
   1234         void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
   1235             EXPECT_EQ(12, mIndex++);
   1236             EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
   1237         }
   1238     };
   1239 
   1240     auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping
   1241             [](RenderProperties& props, RecordingCanvas& canvas) {
   1242         canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
   1243         canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
   1244         canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
   1245         canvas.drawRect(200, 200, 300, 300, SkPaint());
   1246         canvas.restore();
   1247         canvas.restore();
   1248         canvas.restore();
   1249     });
   1250 
   1251     FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600,
   1252             sLightGeometry, Caches::getInstance());
   1253     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   1254 
   1255     SaveLayerUnclippedComplexTestRenderer renderer;
   1256     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1257     EXPECT_EQ(13, renderer.getIndex());
   1258 }
   1259 
   1260 RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
   1261     class HwLayerSimpleTestRenderer : public TestRendererBase {
   1262     public:
   1263         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
   1264             EXPECT_EQ(0, mIndex++);
   1265             EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
   1266             EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
   1267             EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
   1268         }
   1269         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1270             EXPECT_EQ(1, mIndex++);
   1271 
   1272             EXPECT_TRUE(state.computedState.transform.isIdentity())
   1273                     << "Transform should be reset within layer";
   1274 
   1275             EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
   1276                     << "Damage rect should be used to clip layer content";
   1277         }
   1278         void endLayer() override {
   1279             EXPECT_EQ(2, mIndex++);
   1280         }
   1281         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
   1282             EXPECT_EQ(3, mIndex++);
   1283         }
   1284         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
   1285             EXPECT_EQ(4, mIndex++);
   1286         }
   1287         void endFrame(const Rect& repaintRect) override {
   1288             EXPECT_EQ(5, mIndex++);
   1289         }
   1290     };
   1291 
   1292     auto node = TestUtils::createNode(10, 10, 110, 110,
   1293             [](RenderProperties& props, RecordingCanvas& canvas) {
   1294         props.mutateLayerProperties().setType(LayerType::RenderLayer);
   1295         SkPaint paint;
   1296         paint.setColor(SK_ColorWHITE);
   1297         canvas.drawRect(0, 0, 100, 100, paint);
   1298     });
   1299     OffscreenBuffer** layerHandle = node->getLayerHandle();
   1300 
   1301     // create RenderNode's layer here in same way prepareTree would
   1302     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
   1303     *layerHandle = &layer;
   1304 
   1305     auto syncedNode = TestUtils::getSyncedNode(node);
   1306 
   1307     // only enqueue partial damage
   1308     LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
   1309     layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
   1310 
   1311     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1312             sLightGeometry, Caches::getInstance());
   1313     frameBuilder.deferLayers(layerUpdateQueue);
   1314     frameBuilder.deferRenderNode(*syncedNode);
   1315 
   1316     HwLayerSimpleTestRenderer renderer;
   1317     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1318     EXPECT_EQ(6, renderer.getIndex());
   1319 
   1320     // clean up layer pointer, so we can safely destruct RenderNode
   1321     *layerHandle = nullptr;
   1322 }
   1323 
   1324 RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
   1325     /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
   1326      * - startRepaintLayer(child), rect(grey), endLayer
   1327      * - startTemporaryLayer, drawLayer(child), endLayer
   1328      * - startRepaintLayer(parent), rect(white), drawLayer(saveLayer), endLayer
   1329      * - startFrame, drawLayer(parent), endLayerb
   1330      */
   1331     class HwLayerComplexTestRenderer : public TestRendererBase {
   1332     public:
   1333         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
   1334             EXPECT_EQ(3, mIndex++); // savelayer first
   1335             return (OffscreenBuffer*)0xabcd;
   1336         }
   1337         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
   1338             int index = mIndex++;
   1339             if (index == 0) {
   1340                 // starting inner layer
   1341                 EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
   1342                 EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
   1343             } else if (index == 6) {
   1344                 // starting outer layer
   1345                 EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
   1346                 EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
   1347             } else { ADD_FAILURE(); }
   1348         }
   1349         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1350             int index = mIndex++;
   1351             if (index == 1) {
   1352                 // inner layer's rect (white)
   1353                 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
   1354             } else if (index == 7) {
   1355                 // outer layer's rect (grey)
   1356                 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
   1357             } else { ADD_FAILURE(); }
   1358         }
   1359         void endLayer() override {
   1360             int index = mIndex++;
   1361             EXPECT_TRUE(index == 2 || index == 5 || index == 9);
   1362         }
   1363         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
   1364             EXPECT_EQ(10, mIndex++);
   1365         }
   1366         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
   1367             OffscreenBuffer* layer = *op.layerHandle;
   1368             int index = mIndex++;
   1369             if (index == 4) {
   1370                 EXPECT_EQ(100u, layer->viewportWidth);
   1371                 EXPECT_EQ(100u, layer->viewportHeight);
   1372             } else if (index == 8) {
   1373                 EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
   1374             } else if (index == 11) {
   1375                 EXPECT_EQ(200u, layer->viewportWidth);
   1376                 EXPECT_EQ(200u, layer->viewportHeight);
   1377             } else { ADD_FAILURE(); }
   1378         }
   1379         void endFrame(const Rect& repaintRect) override {
   1380             EXPECT_EQ(12, mIndex++);
   1381         }
   1382         void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
   1383             EXPECT_EQ(13, mIndex++);
   1384         }
   1385     };
   1386 
   1387     auto child = TestUtils::createNode(50, 50, 150, 150,
   1388             [](RenderProperties& props, RecordingCanvas& canvas) {
   1389         props.mutateLayerProperties().setType(LayerType::RenderLayer);
   1390         SkPaint paint;
   1391         paint.setColor(SK_ColorWHITE);
   1392         canvas.drawRect(0, 0, 100, 100, paint);
   1393     });
   1394     OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
   1395     *(child->getLayerHandle()) = &childLayer;
   1396 
   1397     RenderNode* childPtr = child.get();
   1398     auto parent = TestUtils::createNode(0, 0, 200, 200,
   1399             [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
   1400         props.mutateLayerProperties().setType(LayerType::RenderLayer);
   1401         SkPaint paint;
   1402         paint.setColor(SK_ColorDKGRAY);
   1403         canvas.drawRect(0, 0, 200, 200, paint);
   1404 
   1405         canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
   1406         canvas.drawRenderNode(childPtr);
   1407         canvas.restore();
   1408     });
   1409     OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
   1410     *(parent->getLayerHandle()) = &parentLayer;
   1411 
   1412     auto syncedNode = TestUtils::getSyncedNode(parent);
   1413 
   1414     LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
   1415     layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
   1416     layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
   1417 
   1418     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1419             sLightGeometry, Caches::getInstance());
   1420     frameBuilder.deferLayers(layerUpdateQueue);
   1421     frameBuilder.deferRenderNode(*syncedNode);
   1422 
   1423     HwLayerComplexTestRenderer renderer;
   1424     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1425     EXPECT_EQ(14, renderer.getIndex());
   1426 
   1427     // clean up layer pointers, so we can safely destruct RenderNodes
   1428     *(child->getLayerHandle()) = nullptr;
   1429     *(parent->getLayerHandle()) = nullptr;
   1430 }
   1431 
   1432 
   1433 RENDERTHREAD_TEST(FrameBuilder, buildLayer) {
   1434     class BuildLayerTestRenderer : public TestRendererBase {
   1435     public:
   1436         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
   1437             EXPECT_EQ(0, mIndex++);
   1438             EXPECT_EQ(100u, offscreenBuffer->viewportWidth);
   1439             EXPECT_EQ(100u, offscreenBuffer->viewportHeight);
   1440             EXPECT_EQ(Rect(25, 25, 75, 75), repaintRect);
   1441         }
   1442         void onColorOp(const ColorOp& op, const BakedOpState& state) override {
   1443             EXPECT_EQ(1, mIndex++);
   1444 
   1445             EXPECT_TRUE(state.computedState.transform.isIdentity())
   1446                     << "Transform should be reset within layer";
   1447 
   1448             EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
   1449                     << "Damage rect should be used to clip layer content";
   1450         }
   1451         void endLayer() override {
   1452             EXPECT_EQ(2, mIndex++);
   1453         }
   1454         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
   1455             ADD_FAILURE() << "Primary frame draw not expected in this test";
   1456         }
   1457         void endFrame(const Rect& repaintRect) override {
   1458             ADD_FAILURE() << "Primary frame draw not expected in this test";
   1459         }
   1460     };
   1461 
   1462     auto node = TestUtils::createNode(10, 10, 110, 110,
   1463             [](RenderProperties& props, RecordingCanvas& canvas) {
   1464         props.mutateLayerProperties().setType(LayerType::RenderLayer);
   1465         canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
   1466     });
   1467     OffscreenBuffer** layerHandle = node->getLayerHandle();
   1468 
   1469     // create RenderNode's layer here in same way prepareTree would
   1470     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
   1471     *layerHandle = &layer;
   1472 
   1473     TestUtils::syncHierarchyPropertiesAndDisplayList(node);
   1474 
   1475     // only enqueue partial damage
   1476     LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
   1477     layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
   1478 
   1479     // Draw, but pass empty node list, so no work is done for primary frame
   1480     FrameBuilder frameBuilder(layerUpdateQueue, sLightGeometry, Caches::getInstance());
   1481     BuildLayerTestRenderer renderer;
   1482     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1483     EXPECT_EQ(3, renderer.getIndex());
   1484 
   1485     // clean up layer pointer, so we can safely destruct RenderNode
   1486     *layerHandle = nullptr;
   1487 }
   1488 
   1489 static void drawOrderedRect(RecordingCanvas* canvas, uint8_t expectedDrawOrder) {
   1490     SkPaint paint;
   1491     // order put in blue channel, transparent so overlapped content doesn't get rejected
   1492     paint.setColor(SkColorSetARGB(1, 0, 0, expectedDrawOrder));
   1493     canvas->drawRect(0, 0, 100, 100, paint);
   1494 }
   1495 static void drawOrderedNode(RecordingCanvas* canvas, uint8_t expectedDrawOrder, float z) {
   1496     auto node = TestUtils::createNode(0, 0, 100, 100,
   1497             [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
   1498         drawOrderedRect(&canvas, expectedDrawOrder);
   1499     });
   1500     node->mutateStagingProperties().setTranslationZ(z);
   1501     node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
   1502     canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
   1503 }
   1504 RENDERTHREAD_TEST(FrameBuilder, zReorder) {
   1505     class ZReorderTestRenderer : public TestRendererBase {
   1506     public:
   1507         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1508             int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
   1509             EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
   1510         }
   1511     };
   1512 
   1513     auto parent = TestUtils::createNode(0, 0, 100, 100,
   1514             [](RenderProperties& props, RecordingCanvas& canvas) {
   1515         drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
   1516         drawOrderedRect(&canvas, 1);
   1517         canvas.insertReorderBarrier(true);
   1518         drawOrderedNode(&canvas, 6, 2.0f);
   1519         drawOrderedRect(&canvas, 3);
   1520         drawOrderedNode(&canvas, 4, 0.0f);
   1521         drawOrderedRect(&canvas, 5);
   1522         drawOrderedNode(&canvas, 2, -2.0f);
   1523         drawOrderedNode(&canvas, 7, 2.0f);
   1524         canvas.insertReorderBarrier(false);
   1525         drawOrderedRect(&canvas, 8);
   1526         drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
   1527     });
   1528     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
   1529             sLightGeometry, Caches::getInstance());
   1530     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
   1531 
   1532     ZReorderTestRenderer renderer;
   1533     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1534     EXPECT_EQ(10, renderer.getIndex());
   1535 };
   1536 
   1537 RENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
   1538     static const int scrollX = 5;
   1539     static const int scrollY = 10;
   1540     class ProjectionReorderTestRenderer : public TestRendererBase {
   1541     public:
   1542         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1543             const int index = mIndex++;
   1544 
   1545             Matrix4 expectedMatrix;
   1546             switch (index) {
   1547             case 0:
   1548                 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
   1549                 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
   1550                 expectedMatrix.loadIdentity();
   1551                 EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
   1552                 break;
   1553             case 1:
   1554                 EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
   1555                 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
   1556                 expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
   1557                 ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
   1558                 EXPECT_EQ(Rect(-35, -30, 45, 50),
   1559                         Rect(state.computedState.localProjectionPathMask->getBounds()));
   1560                 break;
   1561             case 2:
   1562                 EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
   1563                 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
   1564                 expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
   1565                 EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
   1566                 break;
   1567             default:
   1568                 ADD_FAILURE();
   1569             }
   1570             EXPECT_EQ(expectedMatrix, state.computedState.transform);
   1571         }
   1572     };
   1573 
   1574     /**
   1575      * Construct a tree of nodes, where the root (A) has a receiver background (B), and a child (C)
   1576      * with a projecting child (P) of its own. P would normally draw between B and C's "background"
   1577      * draw, but because it is projected backwards, it's drawn in between B and C.
   1578      *
   1579      * The parent is scrolled by scrollX/scrollY, but this does not affect the background
   1580      * (which isn't affected by scroll).
   1581      */
   1582     auto receiverBackground = TestUtils::createNode(0, 0, 100, 100,
   1583             [](RenderProperties& properties, RecordingCanvas& canvas) {
   1584         properties.setProjectionReceiver(true);
   1585         // scroll doesn't apply to background, so undone via translationX/Y
   1586         // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
   1587         properties.setTranslationX(scrollX);
   1588         properties.setTranslationY(scrollY);
   1589 
   1590         SkPaint paint;
   1591         paint.setColor(SK_ColorWHITE);
   1592         canvas.drawRect(0, 0, 100, 100, paint);
   1593     });
   1594     auto projectingRipple = TestUtils::createNode(50, 0, 100, 50,
   1595             [](RenderProperties& properties, RecordingCanvas& canvas) {
   1596         properties.setProjectBackwards(true);
   1597         properties.setClipToBounds(false);
   1598         SkPaint paint;
   1599         paint.setColor(SK_ColorDKGRAY);
   1600         canvas.drawRect(-10, -10, 60, 60, paint);
   1601     });
   1602     auto child = TestUtils::createNode(0, 50, 100, 100,
   1603             [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
   1604         SkPaint paint;
   1605         paint.setColor(SK_ColorBLUE);
   1606         canvas.drawRect(0, 0, 100, 50, paint);
   1607         canvas.drawRenderNode(projectingRipple.get());
   1608     });
   1609     auto parent = TestUtils::createNode(0, 0, 100, 100,
   1610             [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
   1611         // Set a rect outline for the projecting ripple to be masked against.
   1612         properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
   1613 
   1614         canvas.save(SaveFlags::MatrixClip);
   1615         canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
   1616         canvas.drawRenderNode(receiverBackground.get());
   1617         canvas.drawRenderNode(child.get());
   1618         canvas.restore();
   1619     });
   1620 
   1621     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
   1622             sLightGeometry, Caches::getInstance());
   1623     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
   1624 
   1625     ProjectionReorderTestRenderer renderer;
   1626     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1627     EXPECT_EQ(3, renderer.getIndex());
   1628 }
   1629 
   1630 RENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
   1631     static const int scrollX = 5;
   1632     static const int scrollY = 10;
   1633     class ProjectionHwLayerTestRenderer : public TestRendererBase {
   1634     public:
   1635         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
   1636             EXPECT_EQ(0, mIndex++);
   1637         }
   1638         void onArcOp(const ArcOp& op, const BakedOpState& state) override {
   1639             EXPECT_EQ(1, mIndex++);
   1640             ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
   1641         }
   1642         void endLayer() override {
   1643             EXPECT_EQ(2, mIndex++);
   1644         }
   1645         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1646             EXPECT_EQ(3, mIndex++);
   1647             ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
   1648         }
   1649         void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
   1650             EXPECT_EQ(4, mIndex++);
   1651             ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
   1652             Matrix4 expected;
   1653             expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
   1654             EXPECT_EQ(expected, state.computedState.transform);
   1655             EXPECT_EQ(Rect(-85, -80, 295, 300),
   1656                     Rect(state.computedState.localProjectionPathMask->getBounds()));
   1657         }
   1658         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
   1659             EXPECT_EQ(5, mIndex++);
   1660             ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
   1661         }
   1662     };
   1663     auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
   1664             [](RenderProperties& properties, RecordingCanvas& canvas) {
   1665         properties.setProjectionReceiver(true);
   1666         // scroll doesn't apply to background, so undone via translationX/Y
   1667         // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
   1668         properties.setTranslationX(scrollX);
   1669         properties.setTranslationY(scrollY);
   1670 
   1671         canvas.drawRect(0, 0, 400, 400, SkPaint());
   1672     });
   1673     auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
   1674             [](RenderProperties& properties, RecordingCanvas& canvas) {
   1675         properties.setProjectBackwards(true);
   1676         properties.setClipToBounds(false);
   1677         canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
   1678     });
   1679     auto child = TestUtils::createNode(100, 100, 300, 300,
   1680             [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
   1681         properties.mutateLayerProperties().setType(LayerType::RenderLayer);
   1682         canvas.drawRenderNode(projectingRipple.get());
   1683         canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
   1684     });
   1685     auto parent = TestUtils::createNode(0, 0, 400, 400,
   1686             [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
   1687         // Set a rect outline for the projecting ripple to be masked against.
   1688         properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
   1689         canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
   1690         canvas.drawRenderNode(receiverBackground.get());
   1691         canvas.drawRenderNode(child.get());
   1692     });
   1693 
   1694     OffscreenBuffer** layerHandle = child->getLayerHandle();
   1695 
   1696     // create RenderNode's layer here in same way prepareTree would, setting windowTransform
   1697     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
   1698     Matrix4 windowTransform;
   1699     windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
   1700     layer.setWindowTransform(windowTransform);
   1701     *layerHandle = &layer;
   1702 
   1703     auto syncedNode = TestUtils::getSyncedNode(parent);
   1704 
   1705     LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
   1706     layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
   1707 
   1708     FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
   1709             sLightGeometry, Caches::getInstance());
   1710     frameBuilder.deferLayers(layerUpdateQueue);
   1711     frameBuilder.deferRenderNode(*syncedNode);
   1712 
   1713     ProjectionHwLayerTestRenderer renderer;
   1714     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1715     EXPECT_EQ(6, renderer.getIndex());
   1716 
   1717     // clean up layer pointer, so we can safely destruct RenderNode
   1718     *layerHandle = nullptr;
   1719 }
   1720 
   1721 RENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
   1722     static const int scrollX = 500000;
   1723     static const int scrollY = 0;
   1724     class ProjectionChildScrollTestRenderer : public TestRendererBase {
   1725     public:
   1726         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1727             EXPECT_EQ(0, mIndex++);
   1728             EXPECT_TRUE(state.computedState.transform.isIdentity());
   1729         }
   1730         void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
   1731             EXPECT_EQ(1, mIndex++);
   1732             ASSERT_NE(nullptr, state.computedState.clipState);
   1733             ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
   1734             ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
   1735             EXPECT_TRUE(state.computedState.transform.isIdentity());
   1736         }
   1737     };
   1738     auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
   1739             [](RenderProperties& properties, RecordingCanvas& canvas) {
   1740         properties.setProjectionReceiver(true);
   1741         canvas.drawRect(0, 0, 400, 400, SkPaint());
   1742     });
   1743     auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
   1744             [](RenderProperties& properties, RecordingCanvas& canvas) {
   1745         // scroll doesn't apply to background, so undone via translationX/Y
   1746         // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
   1747         properties.setTranslationX(scrollX);
   1748         properties.setTranslationY(scrollY);
   1749         properties.setProjectBackwards(true);
   1750         properties.setClipToBounds(false);
   1751         canvas.drawOval(0, 0, 200, 200, SkPaint());
   1752     });
   1753     auto child = TestUtils::createNode(0, 0, 400, 400,
   1754             [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
   1755         // Record time clip will be ignored by projectee
   1756         canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
   1757 
   1758         canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
   1759         canvas.drawRenderNode(projectingRipple.get());
   1760     });
   1761     auto parent = TestUtils::createNode(0, 0, 400, 400,
   1762             [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
   1763         canvas.drawRenderNode(receiverBackground.get());
   1764         canvas.drawRenderNode(child.get());
   1765     });
   1766 
   1767     FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
   1768             sLightGeometry, Caches::getInstance());
   1769     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
   1770 
   1771     ProjectionChildScrollTestRenderer renderer;
   1772     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1773     EXPECT_EQ(2, renderer.getIndex());
   1774 }
   1775 
   1776 // creates a 100x100 shadow casting node with provided translationZ
   1777 static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
   1778     return TestUtils::createNode(0, 0, 100, 100,
   1779             [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
   1780         properties.setTranslationZ(translationZ);
   1781         properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
   1782         SkPaint paint;
   1783         paint.setColor(SK_ColorWHITE);
   1784         canvas.drawRect(0, 0, 100, 100, paint);
   1785     });
   1786 }
   1787 
   1788 RENDERTHREAD_TEST(FrameBuilder, shadow) {
   1789     class ShadowTestRenderer : public TestRendererBase {
   1790     public:
   1791         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
   1792             EXPECT_EQ(0, mIndex++);
   1793             EXPECT_FLOAT_EQ(1.0f, op.casterAlpha);
   1794             EXPECT_TRUE(op.shadowTask->casterPerimeter.isRect(nullptr));
   1795             EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.shadowTask->transformXY);
   1796 
   1797             Matrix4 expectedZ;
   1798             expectedZ.loadTranslate(0, 0, 5);
   1799             EXPECT_MATRIX_APPROX_EQ(expectedZ, op.shadowTask->transformZ);
   1800         }
   1801         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1802             EXPECT_EQ(1, mIndex++);
   1803         }
   1804     };
   1805 
   1806     auto parent = TestUtils::createNode(0, 0, 200, 200,
   1807             [](RenderProperties& props, RecordingCanvas& canvas) {
   1808         canvas.insertReorderBarrier(true);
   1809         canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
   1810     });
   1811 
   1812     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1813             sLightGeometry, Caches::getInstance());
   1814     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
   1815 
   1816     ShadowTestRenderer renderer;
   1817     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1818     EXPECT_EQ(2, renderer.getIndex());
   1819 }
   1820 
   1821 RENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
   1822     class ShadowSaveLayerTestRenderer : public TestRendererBase {
   1823     public:
   1824         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
   1825             EXPECT_EQ(0, mIndex++);
   1826             return nullptr;
   1827         }
   1828         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
   1829             EXPECT_EQ(1, mIndex++);
   1830             EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
   1831             EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
   1832         }
   1833         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1834             EXPECT_EQ(2, mIndex++);
   1835         }
   1836         void endLayer() override {
   1837             EXPECT_EQ(3, mIndex++);
   1838         }
   1839         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
   1840             EXPECT_EQ(4, mIndex++);
   1841         }
   1842         void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
   1843             EXPECT_EQ(5, mIndex++);
   1844         }
   1845     };
   1846 
   1847     auto parent = TestUtils::createNode(0, 0, 200, 200,
   1848             [](RenderProperties& props, RecordingCanvas& canvas) {
   1849         // save/restore outside of reorderBarrier, so they don't get moved out of place
   1850         canvas.translate(20, 10);
   1851         int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
   1852         canvas.insertReorderBarrier(true);
   1853         canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
   1854         canvas.insertReorderBarrier(false);
   1855         canvas.restoreToCount(count);
   1856     });
   1857 
   1858     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1859             (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
   1860     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
   1861 
   1862     ShadowSaveLayerTestRenderer renderer;
   1863     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1864     EXPECT_EQ(6, renderer.getIndex());
   1865 }
   1866 
   1867 RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
   1868     class ShadowHwLayerTestRenderer : public TestRendererBase {
   1869     public:
   1870         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
   1871             EXPECT_EQ(0, mIndex++);
   1872         }
   1873         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
   1874             EXPECT_EQ(1, mIndex++);
   1875             EXPECT_FLOAT_EQ(50, op.shadowTask->lightCenter.x);
   1876             EXPECT_FLOAT_EQ(40, op.shadowTask->lightCenter.y);
   1877             EXPECT_FLOAT_EQ(30, op.shadowTask->lightRadius);
   1878         }
   1879         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1880             EXPECT_EQ(2, mIndex++);
   1881         }
   1882         void endLayer() override {
   1883             EXPECT_EQ(3, mIndex++);
   1884         }
   1885         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
   1886             EXPECT_EQ(4, mIndex++);
   1887         }
   1888     };
   1889 
   1890     auto parent = TestUtils::createNode(50, 60, 150, 160,
   1891             [](RenderProperties& props, RecordingCanvas& canvas) {
   1892         props.mutateLayerProperties().setType(LayerType::RenderLayer);
   1893         canvas.insertReorderBarrier(true);
   1894         canvas.save(SaveFlags::MatrixClip);
   1895         canvas.translate(20, 10);
   1896         canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
   1897         canvas.restore();
   1898     });
   1899     OffscreenBuffer** layerHandle = parent->getLayerHandle();
   1900 
   1901     // create RenderNode's layer here in same way prepareTree would, setting windowTransform
   1902     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
   1903     Matrix4 windowTransform;
   1904     windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
   1905     layer.setWindowTransform(windowTransform);
   1906     *layerHandle = &layer;
   1907 
   1908     auto syncedNode = TestUtils::getSyncedNode(parent);
   1909     LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
   1910     layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
   1911 
   1912     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1913             (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
   1914     frameBuilder.deferLayers(layerUpdateQueue);
   1915     frameBuilder.deferRenderNode(*syncedNode);
   1916 
   1917     ShadowHwLayerTestRenderer renderer;
   1918     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1919     EXPECT_EQ(5, renderer.getIndex());
   1920 
   1921     // clean up layer pointer, so we can safely destruct RenderNode
   1922     *layerHandle = nullptr;
   1923 }
   1924 
   1925 RENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
   1926     class ShadowLayeringTestRenderer : public TestRendererBase {
   1927     public:
   1928         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
   1929             int index = mIndex++;
   1930             EXPECT_TRUE(index == 0 || index == 1);
   1931         }
   1932         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1933             int index = mIndex++;
   1934             EXPECT_TRUE(index == 2 || index == 3);
   1935         }
   1936     };
   1937     auto parent = TestUtils::createNode(0, 0, 200, 200,
   1938             [](RenderProperties& props, RecordingCanvas& canvas) {
   1939         canvas.insertReorderBarrier(true);
   1940         canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
   1941         canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
   1942     });
   1943     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   1944             (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
   1945     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
   1946 
   1947     ShadowLayeringTestRenderer renderer;
   1948     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1949     EXPECT_EQ(4, renderer.getIndex());
   1950 }
   1951 
   1952 RENDERTHREAD_TEST(FrameBuilder, shadowClipping) {
   1953     class ShadowClippingTestRenderer : public TestRendererBase {
   1954     public:
   1955         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
   1956             EXPECT_EQ(0, mIndex++);
   1957             EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipState->rect)
   1958                     << "Shadow must respect pre-barrier canvas clip value.";
   1959         }
   1960         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1961             EXPECT_EQ(1, mIndex++);
   1962         }
   1963     };
   1964     auto parent = TestUtils::createNode(0, 0, 100, 100,
   1965             [](RenderProperties& props, RecordingCanvas& canvas) {
   1966         // Apply a clip before the reorder barrier/shadow casting child is drawn.
   1967         // This clip must be applied to the shadow cast by the child.
   1968         canvas.clipRect(25, 25, 75, 75, SkRegion::kIntersect_Op);
   1969         canvas.insertReorderBarrier(true);
   1970         canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
   1971     });
   1972 
   1973     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
   1974             (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
   1975     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
   1976 
   1977     ShadowClippingTestRenderer renderer;
   1978     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   1979     EXPECT_EQ(2, renderer.getIndex());
   1980 }
   1981 
   1982 static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
   1983         std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
   1984     class PropertyTestRenderer : public TestRendererBase {
   1985     public:
   1986         PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
   1987                 : mCallback(callback) {}
   1988         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   1989             EXPECT_EQ(mIndex++, 0);
   1990             mCallback(op, state);
   1991         }
   1992         std::function<void(const RectOp&, const BakedOpState&)> mCallback;
   1993     };
   1994 
   1995     auto node = TestUtils::createNode(0, 0, 100, 100,
   1996             [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
   1997         propSetupCallback(props);
   1998         SkPaint paint;
   1999         paint.setColor(SK_ColorWHITE);
   2000         canvas.drawRect(0, 0, 100, 100, paint);
   2001     });
   2002 
   2003     FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
   2004             sLightGeometry, Caches::getInstance());
   2005     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   2006 
   2007     PropertyTestRenderer renderer(opValidateCallback);
   2008     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   2009     EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
   2010 }
   2011 
   2012 RENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
   2013     testProperty([](RenderProperties& properties) {
   2014         properties.setAlpha(0.5f);
   2015         properties.setHasOverlappingRendering(false);
   2016     }, [](const RectOp& op, const BakedOpState& state) {
   2017         EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
   2018     });
   2019 }
   2020 
   2021 RENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
   2022     testProperty([](RenderProperties& properties) {
   2023         properties.setClipToBounds(true);
   2024         properties.setClipBounds(Rect(10, 20, 300, 400));
   2025     }, [](const RectOp& op, const BakedOpState& state) {
   2026         EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
   2027                 << "Clip rect should be intersection of node bounds and clip bounds";
   2028     });
   2029 }
   2030 
   2031 RENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
   2032     testProperty([](RenderProperties& properties) {
   2033         properties.mutableRevealClip().set(true, 50, 50, 25);
   2034     }, [](const RectOp& op, const BakedOpState& state) {
   2035         ASSERT_NE(nullptr, state.roundRectClipState);
   2036         EXPECT_TRUE(state.roundRectClipState->highPriority);
   2037         EXPECT_EQ(25, state.roundRectClipState->radius);
   2038         EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
   2039     });
   2040 }
   2041 
   2042 RENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
   2043     testProperty([](RenderProperties& properties) {
   2044         properties.mutableOutline().setShouldClip(true);
   2045         properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
   2046     }, [](const RectOp& op, const BakedOpState& state) {
   2047         ASSERT_NE(nullptr, state.roundRectClipState);
   2048         EXPECT_FALSE(state.roundRectClipState->highPriority);
   2049         EXPECT_EQ(5, state.roundRectClipState->radius);
   2050         EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
   2051     });
   2052 }
   2053 
   2054 RENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
   2055     testProperty([](RenderProperties& properties) {
   2056         properties.setLeftTopRightBottom(10, 10, 110, 110);
   2057 
   2058         SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
   2059         properties.setStaticMatrix(&staticMatrix);
   2060 
   2061         // ignored, since static overrides animation
   2062         SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
   2063         properties.setAnimationMatrix(&animationMatrix);
   2064 
   2065         properties.setTranslationX(10);
   2066         properties.setTranslationY(20);
   2067         properties.setScaleX(0.5f);
   2068         properties.setScaleY(0.7f);
   2069     }, [](const RectOp& op, const BakedOpState& state) {
   2070         Matrix4 matrix;
   2071         matrix.loadTranslate(10, 10, 0); // left, top
   2072         matrix.scale(1.2f, 1.2f, 1); // static matrix
   2073         // ignore animation matrix, since static overrides it
   2074 
   2075         // translation xy
   2076         matrix.translate(10, 20);
   2077 
   2078         // scale xy (from default pivot - center)
   2079         matrix.translate(50, 50);
   2080         matrix.scale(0.5f, 0.7f, 1);
   2081         matrix.translate(-50, -50);
   2082         EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
   2083                 << "Op draw matrix must match expected combination of transformation properties";
   2084     });
   2085 }
   2086 
   2087 struct SaveLayerAlphaData {
   2088     uint32_t layerWidth = 0;
   2089     uint32_t layerHeight = 0;
   2090     Rect rectClippedBounds;
   2091     Matrix4 rectMatrix;
   2092     Matrix4 drawLayerMatrix;
   2093 };
   2094 /**
   2095  * Constructs a view to hit the temporary layer alpha property implementation:
   2096  *     a) 0 < alpha < 1
   2097  *     b) too big for layer (larger than maxTextureSize)
   2098  *     c) overlapping rendering content
   2099  * returning observed data about layer size and content clip/transform.
   2100  *
   2101  * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
   2102  * (for efficiency, and to fit in layer size constraints) based on parent clip.
   2103  */
   2104 void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
   2105         std::function<void(RenderProperties&)> propSetupCallback) {
   2106     class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
   2107     public:
   2108         SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
   2109                 : mOutData(outData) {}
   2110 
   2111         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
   2112             EXPECT_EQ(0, mIndex++);
   2113             mOutData->layerWidth = width;
   2114             mOutData->layerHeight = height;
   2115             return nullptr;
   2116         }
   2117         void onRectOp(const RectOp& op, const BakedOpState& state) override {
   2118             EXPECT_EQ(1, mIndex++);
   2119 
   2120             mOutData->rectClippedBounds = state.computedState.clippedBounds;
   2121             mOutData->rectMatrix = state.computedState.transform;
   2122         }
   2123         void endLayer() override {
   2124             EXPECT_EQ(2, mIndex++);
   2125         }
   2126         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
   2127             EXPECT_EQ(3, mIndex++);
   2128             mOutData->drawLayerMatrix = state.computedState.transform;
   2129         }
   2130         void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
   2131             EXPECT_EQ(4, mIndex++);
   2132         }
   2133     private:
   2134         SaveLayerAlphaData* mOutData;
   2135     };
   2136 
   2137     ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
   2138             << "Node must be bigger than max texture size to exercise saveLayer codepath";
   2139     auto node = TestUtils::createNode(0, 0, 10000, 10000,
   2140             [&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
   2141         properties.setHasOverlappingRendering(true);
   2142         properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
   2143         // apply other properties
   2144         propSetupCallback(properties);
   2145 
   2146         SkPaint paint;
   2147         paint.setColor(SK_ColorWHITE);
   2148         canvas.drawRect(0, 0, 10000, 10000, paint);
   2149     });
   2150     auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
   2151 
   2152     FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
   2153                 sLightGeometry, Caches::getInstance());
   2154     frameBuilder.deferRenderNode(*syncedNode);
   2155 
   2156     SaveLayerAlphaClipTestRenderer renderer(outObservedData);
   2157     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   2158 
   2159     // assert, since output won't be valid if we haven't seen a save layer triggered
   2160     ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
   2161 }
   2162 
   2163 RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
   2164     SaveLayerAlphaData observedData;
   2165     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
   2166         properties.setTranslationX(10); // offset rendering content
   2167         properties.setTranslationY(-2000); // offset rendering content
   2168     });
   2169     EXPECT_EQ(190u, observedData.layerWidth);
   2170     EXPECT_EQ(200u, observedData.layerHeight);
   2171     EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
   2172             << "expect content to be clipped to screen area";
   2173     Matrix4 expected;
   2174     expected.loadTranslate(0, -2000, 0);
   2175     EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
   2176             << "expect content to be translated as part of being clipped";
   2177     expected.loadTranslate(10, 0, 0);
   2178     EXPECT_MATRIX_APPROX_EQ(expected, observedData.drawLayerMatrix)
   2179                 << "expect drawLayer to be translated as part of being clipped";
   2180 }
   2181 
   2182 RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
   2183     SaveLayerAlphaData observedData;
   2184     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
   2185         // Translate and rotate the view so that the only visible part is the top left corner of
   2186         // the view. It will form an isosceles right triangle with a long side length of 200 at the
   2187         // bottom of the viewport.
   2188         properties.setTranslationX(100);
   2189         properties.setTranslationY(100);
   2190         properties.setPivotX(0);
   2191         properties.setPivotY(0);
   2192         properties.setRotation(45);
   2193     });
   2194     // ceil(sqrt(2) / 2 * 200) = 142
   2195     EXPECT_EQ(142u, observedData.layerWidth);
   2196     EXPECT_EQ(142u, observedData.layerHeight);
   2197     EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
   2198     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
   2199 }
   2200 
   2201 RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
   2202     SaveLayerAlphaData observedData;
   2203     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
   2204         properties.setPivotX(0);
   2205         properties.setPivotY(0);
   2206         properties.setScaleX(2);
   2207         properties.setScaleY(0.5f);
   2208     });
   2209     EXPECT_EQ(100u, observedData.layerWidth);
   2210     EXPECT_EQ(400u, observedData.layerHeight);
   2211     EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
   2212     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
   2213 }
   2214 
   2215 RENDERTHREAD_TEST(FrameBuilder, clip_replace) {
   2216     class ClipReplaceTestRenderer : public TestRendererBase {
   2217     public:
   2218         void onColorOp(const ColorOp& op, const BakedOpState& state) override {
   2219             EXPECT_EQ(0, mIndex++);
   2220             EXPECT_TRUE(op.localClip->intersectWithRoot);
   2221             EXPECT_EQ(Rect(20, 10, 30, 40), state.computedState.clipState->rect)
   2222                     << "Expect resolved clip to be intersection of viewport clip and clip op";
   2223         }
   2224     };
   2225     auto node = TestUtils::createNode(20, 20, 30, 30,
   2226             [](RenderProperties& props, RecordingCanvas& canvas) {
   2227         canvas.clipRect(0, -20, 10, 30, SkRegion::kReplace_Op);
   2228         canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
   2229     });
   2230 
   2231     FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
   2232             sLightGeometry, Caches::getInstance());
   2233     frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
   2234 
   2235     ClipReplaceTestRenderer renderer;
   2236     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
   2237     EXPECT_EQ(1, renderer.getIndex());
   2238 }
   2239 
   2240 } // namespace uirenderer
   2241 } // namespace android
   2242