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