Workaround arc textures drawing outside of bounds

Fixes: 34077513
Test: hwui unit tests passing

This fixes an issue where drawArc operations would cause artifacts by
drawing outside of the clip / screen damage area. We now more
conservatively clip drawArc operations specifically, as they tend to
draw into the outer parts of their path textures more than other
operations.

A more long term fix would involve alignment between draw operation
sizing (in terms of what's resolved in a BakedOpState), and
PathTexture sizing (which currently conservatively expands beyond
stroked op bounds).

Change-Id: I5aff39cc04382323b457b159974032f5f371251a
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 9f98241..9823a02 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -31,7 +31,7 @@
 }
 
 ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
-        const RecordedOp& recordedOp, bool expandForStroke) {
+        const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) {
     // resolvedMatrix = parentMatrix * localMatrix
     transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
 
@@ -40,6 +40,8 @@
     if (CC_UNLIKELY(expandForStroke)) {
         // account for non-hairline stroke
         clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
+    } else if (CC_UNLIKELY(expandForPathTexture)) {
+        clippedBounds.outset(1);
     }
     transform.mapRect(clippedBounds);
     if (CC_UNLIKELY(expandForStroke
@@ -111,7 +113,7 @@
         Snapshot& snapshot, const RecordedOp& recordedOp) {
     if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
     BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
-            allocator, snapshot, recordedOp, false);
+            allocator, snapshot, recordedOp, false, false);
     if (bakedState->computedState.clippedBounds.isEmpty()) {
         // bounds are empty, so op is rejected
         allocator.rewindIfLastAlloc(bakedState);
@@ -127,14 +129,14 @@
 }
 
 BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
-        Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+        Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
+        bool expandForPathTexture) {
     if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
-    bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
-            ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
-            : true;
+    bool expandForStroke = (strokeBehavior == StrokeBehavior::Forced
+            || (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
 
     BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
-           allocator, snapshot, recordedOp, expandForStroke);
+           allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
     if (bakedState->computedState.clippedBounds.isEmpty()) {
         // bounds are empty, so op is rejected
         // NOTE: this won't succeed if a clip was allocated