Handle unbounded drawPaint/drawGLFunction operations safely

bug:26591194

Also, revert to using current clip bounds as drawColor/drawPaint bounds
for simplicity in new pipeline.

Change-Id: I1a6b3f9716b564b46df41d57dfe14475fdd24de0
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 26653f7..85903654 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -82,6 +82,16 @@
     }
 }
 
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+        const Matrix4& localTransform, const ClipBase* localClip) {
+    transform.loadMultiply(*snapshot.transform, localTransform);
+    clipState = snapshot.mutateClipArea().serializeIntersectedClip(allocator,
+            localClip, *(snapshot.transform));
+    clippedBounds = clipState->rect;
+    clipSideFlags = OpClipSideFlags::Full;
+    localProjectionPathMask = nullptr;
+}
+
 ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot)
         : transform(*snapshot.transform)
         , clipState(snapshot.mutateClipArea().serializeClip(allocator))
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index ffe2901..4e3cb8a 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -55,6 +55,10 @@
     ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
             const RecordedOp& recordedOp, bool expandForStroke);
 
+    // Constructor for unbounded ops *with* transform/clip
+    ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+            const Matrix4& localTransform, const ClipBase* localClip);
+
     // Constructor for unbounded ops without transform/clip (namely shadows)
     ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
 
@@ -111,8 +115,14 @@
         return bakedState;
     }
 
+    static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator,
+            Snapshot& snapshot, const RecordedOp& recordedOp) {
+        if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
+        return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
+    }
+
     enum class StrokeBehavior {
-        // stroking is forced, regardless of style on paint
+        // stroking is forced, regardless of style on paint (such as for lines)
         Forced,
         // stroking is defined by style on paint
         StyleDefined,
@@ -167,6 +177,13 @@
             , roundRectClipState(snapshot.roundRectClipState)
             , op(&recordedOp) {}
 
+    // TODO: fix this brittleness
+    BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp)
+            : computedState(allocator, snapshot, recordedOp.localMatrix, recordedOp.localClip)
+            , alpha(snapshot.alpha)
+            , roundRectClipState(snapshot.roundRectClipState)
+            , op(&recordedOp) {}
+
     BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr)
             : computedState(allocator, snapshot)
             , alpha(snapshot.alpha)
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index fd5856a..2855db0 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -574,7 +574,7 @@
 }
 
 void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
+    BakedOpState* bakedState = tryBakeUnboundedOpState(op);
     if (!bakedState) return; // quick rejected
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
 }
@@ -661,7 +661,7 @@
 }
 
 void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
-    BakedOpState* bakedState = tryBakeOpState(op);
+    BakedOpState* bakedState = tryBakeUnboundedOpState(op);
     if (!bakedState) return; // quick rejected
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
 }
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index f44306a..8a00d33 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -173,6 +173,10 @@
     BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
         return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
     }
+    BakedOpState* tryBakeUnboundedOpState(const RecordedOp& recordedOp) {
+        return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
+    }
+
 
     // should always be surrounded by a save/restore pair, and not called if DisplayList is null
     void deferNodePropsAndOps(RenderNode& node);
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index c37458d..96a57b6 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -257,8 +257,10 @@
 };
 
 struct FunctorOp : RecordedOp {
-    FunctorOp(BASE_PARAMS_PAINTLESS, Functor* functor)
-            : SUPER_PAINTLESS(FunctorOp)
+    // Note: undefined record-time bounds, since this op fills the clip
+    // TODO: explicitly define bounds
+    FunctorOp(const Matrix4& localMatrix, const ClipBase* localClip, Functor* functor)
+            : RecordedOp(RecordedOpId::FunctorOp, Rect(), localMatrix, localClip, nullptr)
             , functor(functor) {}
     Functor* functor;
 };
@@ -385,9 +387,10 @@
 };
 
 struct TextOnPathOp : RecordedOp {
-    TextOnPathOp(BASE_PARAMS, const glyph_t* glyphs, int glyphCount,
-            const SkPath* path, float hOffset, float vOffset)
-            : SUPER(TextOnPathOp)
+    // TODO: explicitly define bounds
+    TextOnPathOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
+            const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset, float vOffset)
+            : RecordedOp(RecordedOpId::TextOnPathOp, Rect(), localMatrix, localClip, paint)
             , glyphs(glyphs)
             , glyphCount(glyphCount)
             , path(path)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 11eb825..1546baf 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -24,14 +24,6 @@
 namespace android {
 namespace uirenderer {
 
-#define MIL_PIX 1000000
-static Rect sUnreasonablyLargeBounds(-MIL_PIX, -MIL_PIX, MIL_PIX, MIL_PIX);
-
-static const Rect& getConservativeOpBounds(const ClipBase* clip) {
-    // if op is clipped, that rect can be used, but otherwise just use a conservatively large rect
-    return clip ? clip->rect : sUnreasonablyLargeBounds;
-}
-
 RecordingCanvas::RecordingCanvas(size_t width, size_t height)
         : mState(*this)
         , mResourceCache(ResourceCache::getInstance()) {
@@ -249,12 +241,10 @@
 }
 
 void RecordingCanvas::drawPaint(const SkPaint& paint) {
-    const ClipBase* clip = getRecordedClip();
-    addOp(alloc().create_trivial<RectOp>(
-            getConservativeOpBounds(clip),
-            Matrix4::identity(),
-            clip,
-            refPaint(&paint)));
+    SkRect bounds;
+    if (getClipBounds(&bounds)) {
+        drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint);
+    }
 }
 
 static Rect calcBoundsOfPoints(const float* points, int floatCount) {
@@ -544,11 +534,9 @@
             float hOffset, float vOffset, const SkPaint& paint) {
     if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
     glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
-    auto clip = getRecordedClip();
     addOp(alloc().create_trivial<TextOnPathOp>(
-            getConservativeOpBounds(clip), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
-            clip,
+            getRecordedClip(),
             refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
 }
 
@@ -599,11 +587,9 @@
 
 void RecordingCanvas::callDrawGLFunction(Functor* functor) {
     mDisplayList->functors.push_back(functor);
-    auto clip = getRecordedClip();
     addOp(alloc().create_trivial<FunctorOp>(
-            getConservativeOpBounds(clip),
             *(mState.currentSnapshot()->transform),
-            clip,
+            getRecordedClip(),
             functor));
 }
 
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 5e613fd..e6d84c6 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -223,8 +223,7 @@
     auto op = *(dl->getOps()[0]);
     EXPECT_EQ(RecordedOpId::RectOp, op.opId);
     EXPECT_EQ(nullptr, op.localClip);
-    EXPECT_TRUE(op.unmappedBounds.contains(Rect(-1000, -1000, 1000, 1000)))
-            << "no clip, unmappedBounds should resolve to be much larger than DL bounds";
+    EXPECT_TRUE(op.unmappedBounds.contains(Rect(200, 200))) << "Expect recording/clip bounds";
 }
 
 TEST(RecordingCanvas, backgroundAndImage) {