Merge "Create first class unbounded ColorOp" into nyc-dev am: 349c866
am: d4abb25

* commit 'd4abb2527bae306dd3fd935e6fddd7b7899d100a':
  Create first class unbounded ColorOp
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 06b712e..ea4f4eb 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -506,6 +506,22 @@
     renderer.renderGlop(state, glop);
 }
 
+void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) {
+    SkPaint paint;
+    paint.setColor(op.color);
+    paint.setXfermodeMode(op.mode);
+
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshUnitQuad()
+            .setFillPaint(paint, state.alpha)
+            .setTransform(Matrix4::identity(), TransformFlags::None)
+            .setModelViewMapUnitToRect(state.computedState.clipState->rect)
+            .build();
+    renderer.renderGlop(state, glop);
+}
+
 void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
     renderer.renderFunctor(op, state);
 }
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index fae8e48..0ebb886 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -572,6 +572,12 @@
     deferOvalOp(*resolvedOp);
 }
 
+void FrameBuilder::deferColorOp(const ColorOp& op) {
+    BakedOpState* bakedState = tryBakeUnboundedOpState(op);
+    if (!bakedState) return; // quick rejected
+    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
+}
+
 void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
     BakedOpState* bakedState = tryBakeUnboundedOpState(op);
     if (!bakedState) return; // quick rejected
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 96a57b6..64c604a 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -90,6 +90,7 @@
         UNMERGEABLE_OP_FN(ArcOp) \
         UNMERGEABLE_OP_FN(BitmapMeshOp) \
         UNMERGEABLE_OP_FN(BitmapRectOp) \
+        UNMERGEABLE_OP_FN(ColorOp) \
         UNMERGEABLE_OP_FN(FunctorOp) \
         UNMERGEABLE_OP_FN(LinesOp) \
         UNMERGEABLE_OP_FN(OvalOp) \
@@ -256,6 +257,16 @@
     const float* radius;
 };
 
+struct ColorOp : RecordedOp {
+    // Note: unbounded op that will fillclip, so no bounds/matrix needed
+    ColorOp(const ClipBase* localClip, int color, SkXfermode::Mode mode)
+            : RecordedOp(RecordedOpId::ColorOp, Rect(), Matrix4::identity(), localClip, nullptr)
+            , color(color)
+            , mode(mode) {}
+    const int color;
+    const SkXfermode::Mode mode;
+};
+
 struct FunctorOp : RecordedOp {
     // Note: undefined record-time bounds, since this op fills the clip
     // TODO: explicitly define bounds
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 4eeadb7..f43dade 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -234,10 +234,10 @@
 // android/graphics/Canvas draw operations
 // ----------------------------------------------------------------------------
 void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
-    SkPaint paint;
-    paint.setColor(color);
-    paint.setXfermodeMode(mode);
-    drawPaint(paint);
+    addOp(alloc().create_trivial<ColorOp>(
+            getRecordedClip(),
+            color,
+            mode));
 }
 
 void RecordingCanvas::drawPaint(const SkPaint& paint) {
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index ba22d91..dca56d4 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -427,7 +427,31 @@
     EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderNode) {
+RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
+    class ColorTestRenderer : public TestRendererBase {
+    public:
+        void onColorOp(const ColorOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds)
+                    << "Color op should be expanded to bounds of surrounding";
+        }
+    };
+
+    auto unclippedColorView = TestUtils::createNode(0, 0, 10, 10,
+            [](RenderProperties& props, RecordingCanvas& canvas) {
+        props.setClipToBounds(false);
+        canvas.drawColor(SK_ColorWHITE, SkXfermode::Mode::kSrcOver_Mode);
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+            TestUtils::createSyncedNodeList(unclippedColorView),
+            sLightGeometry, Caches::getInstance());
+    ColorTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
+}
+
+TEST(FrameBuilder, renderNode) {
     class RenderNodeTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 42dabd3..1c240db 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -226,9 +226,9 @@
 
     ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
     auto op = *(dl->getOps()[0]);
-    EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+    EXPECT_EQ(RecordedOpId::ColorOp, op.opId);
     EXPECT_EQ(nullptr, op.localClip);
-    EXPECT_TRUE(op.unmappedBounds.contains(Rect(200, 200))) << "Expect recording/clip bounds";
+    EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds";
 }
 
 TEST(RecordingCanvas, backgroundAndImage) {