Cap scales used for tessellation with minimum and maximum

bug:15615144
Change-Id: I3e833864af3a7b34e444bd13db34b6c90496a8b6
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 910f862..a410aa9 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -386,9 +386,6 @@
 
     @Override
     public void scale(float sx, float sy) {
-        // TODO: remove
-        if (sx > 1000000 || sy > 1000000) throw new IllegalArgumentException("invalid scales passed " + sx + ", " + sy);
-
         nScale(mRenderer, sx, sy);
     }
 
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index eee4973..099f153 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -598,9 +598,6 @@
      * @see #getScaleX()
      */
     public boolean setScaleX(float scaleX) {
-        if (scaleX > 1000000) {
-            throw new IllegalArgumentException("Invalid scale: " + scaleX);
-        }
         return nSetScaleX(mNativeRenderNode, scaleX);
     }
 
@@ -622,9 +619,6 @@
      * @see #getScaleY()
      */
     public boolean setScaleY(float scaleY) {
-        if (scaleY > 1000000) {
-            throw new IllegalArgumentException("Invalid scale: " + scaleY);
-        }
         return nSetScaleY(mNativeRenderNode, scaleY);
     }
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e00d2e3..396c7f3 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -58,11 +58,6 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-#define RAD_TO_DEG (180.0f / 3.14159265f)
-#define MIN_ANGLE 0.001f
-
-#define ALPHA_THRESHOLD 0
-
 static GLenum getFilter(const SkPaint* paint) {
     if (!paint || paint->getFilterLevel() != SkPaint::kNone_FilterLevel) {
         return GL_LINEAR;
@@ -692,7 +687,7 @@
             (fboLayer && clip.isEmpty())) {
         mSnapshot->empty = fboLayer;
     } else {
-        mSnapshot->invisible = mSnapshot->invisible || (alpha <= ALPHA_THRESHOLD && fboLayer);
+        mSnapshot->invisible = mSnapshot->invisible || (alpha <= 0 && fboLayer);
     }
 }
 
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 209341c..e30ac19 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -49,6 +49,7 @@
 #include "Matrix.h"
 #include "Vector.h"
 #include "Vertex.h"
+#include "utils/MathUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -56,12 +57,11 @@
 #define OUTLINE_REFINE_THRESHOLD_SQUARED (0.5f * 0.5f)
 #define ROUND_CAP_THRESH 0.25f
 #define PI 3.1415926535897932f
+#define MAX_DEPTH 15
 
-// temporary error thresholds
-#define ERROR_DEPTH 20
-#define ERROR_SCALE 1e10
-#define ERROR_SQR_INV_THRESH 1e-20
-
+/**
+ * Extracts the x and y scale from the transform as positive values, and clamps them
+ */
 void PathTessellator::extractTessellationScales(const Matrix4& transform,
         float* scaleX, float* scaleY) {
     if (CC_LIKELY(transform.isPureTranslate())) {
@@ -72,11 +72,8 @@
         float m01 = transform.data[Matrix4::kSkewY];
         float m10 = transform.data[Matrix4::kSkewX];
         float m11 = transform.data[Matrix4::kScaleY];
-        *scaleX = sqrt(m00 * m00 + m01 * m01);
-        *scaleY = sqrt(m10 * m10 + m11 * m11);
-
-        LOG_ALWAYS_FATAL_IF(*scaleX > ERROR_SCALE || *scaleY > ERROR_SCALE,
-                "scales %e x %e too large for tessellation", *scaleX, *scaleY);
+        *scaleX = MathUtils::clampTessellationScale(sqrt(m00 * m00 + m01 * m01));
+        *scaleY = MathUtils::clampTessellationScale(sqrt(m10 * m10 + m11 * m11));
     }
 }
 
@@ -109,8 +106,8 @@
         } else {
             float scaleX, scaleY;
             PathTessellator::extractTessellationScales(transform, &scaleX, &scaleY);
-            inverseScaleX = (scaleX != 0) ? (1.0f / scaleX) : 1.0f;
-            inverseScaleY = (scaleY != 0) ? (1.0f / scaleY) : 1.0f;
+            inverseScaleX = 1.0f / scaleX;
+            inverseScaleY = 1.0f / scaleY;
         }
 
         if (isAA && halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
@@ -914,9 +911,6 @@
         Vector<Vertex>& outputVertices) {
     ATRACE_CALL();
 
-    LOG_ALWAYS_FATAL_IF(sqrInvScaleX < ERROR_SQR_INV_THRESH || sqrInvScaleY < ERROR_SQR_INV_THRESH,
-            "Invalid scale factors used for approx %e, %e", sqrInvScaleX, sqrInvScaleY);
-
     // TODO: to support joins other than sharp miter, join vertices should be labelled in the
     // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case.
     SkPath::Iter iter(path, forceClose);
@@ -975,9 +969,6 @@
         float p2x, float p2y, float c2x, float c2y,
         float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
         Vector<Vertex>& outputVertices, int depth) {
-    LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR DEPTH exceeded: cubic approx, invscale %e x %e, vertcount %d",
-            sqrInvScaleX, sqrInvScaleY, outputVertices.size());
-
     float dx = p2x - p1x;
     float dy = p2y - p1y;
     float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
@@ -985,7 +976,8 @@
     float d = d1 + d2;
 
     // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
-    if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+    if (depth >= MAX_DEPTH
+            || d * d <= thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
         // below thresh, draw line by adding endpoint
         pushToVector(outputVertices, p2x, p2y);
     } else {
@@ -1023,14 +1015,13 @@
         float cx, float cy,
         float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
         Vector<Vertex>& outputVertices, int depth) {
-    LOG_ALWAYS_FATAL_IF(depth >= ERROR_DEPTH, "ERROR_DEPTH exceeded: quadratic approx, invscale %e x %e, vertcount %d",
-            sqrInvScaleX, sqrInvScaleY, outputVertices.size());
-
     float dx = bx - ax;
     float dy = by - ay;
     float d = (cx - bx) * dy - (cy - by) * dx;
 
-    if (d * d < thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
+    // multiplying by sqrInvScaleY/X equivalent to multiplying in dimensional scale factors
+    if (depth >= MAX_DEPTH
+            || d * d <= thresholdSquared * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) {
         // below thresh, draw line by adding endpoint
         pushToVector(outputVertices, bx, by);
     } else {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 41f48cd..0c8d07f 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -313,7 +313,6 @@
     }
 
     bool setScaleX(float scaleX) {
-        LOG_ALWAYS_FATAL_IF(scaleX > 1000000, "invalid scaleX %e", scaleX);
         return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
     }
 
@@ -322,7 +321,6 @@
     }
 
     bool setScaleY(float scaleY) {
-        LOG_ALWAYS_FATAL_IF(scaleY > 1000000, "invalid scaleY %e", scaleY);
         return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
     }
 
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 66bc127..6fb0411 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -35,6 +35,9 @@
         return value >= NON_ZERO_EPSILON;
     }
 
+    /**
+     * Clamps alpha value, and snaps when very near 0 or 1
+     */
     inline static float clampAlpha(float alpha) {
         if (alpha <= ALPHA_EPSILON) {
             return 0;
@@ -45,6 +48,20 @@
         }
     }
 
+    /*
+     * Clamps positive tessellation scale values
+     */
+    inline static float clampTessellationScale(float scale) {
+        const float MIN_SCALE = 0.0001;
+        const float MAX_SCALE = 1e10;
+        if (scale < MIN_SCALE) {
+            return MIN_SCALE;
+        } else if (scale > MAX_SCALE) {
+            return MAX_SCALE;
+        }
+        return scale;
+    }
+
     inline static bool areEqual(float valueA, float valueB) {
         return isZero(valueA - valueB);
     }