Update Skia's NinePatch decoder

This CL enables the decoder to handle collapsing the stretchy
area along one axis while still stretching the other. This prevents
us from falling into the standard bitmap strech and produces better
looking results.

bug: 5239166
Change-Id: Iadde581d7853430c6fd59446959a34661a19e927
diff --git a/src/utils/SkNinePatch.cpp b/src/utils/SkNinePatch.cpp
index bbda573..c416fa6 100644
--- a/src/utils/SkNinePatch.cpp
+++ b/src/utils/SkNinePatch.cpp
@@ -53,6 +53,31 @@
     return indices - startIndices;
 }
 
+// Computes the delta between vertices along a single axis
+static SkScalar computeVertexDelta(bool isStretchyVertex,
+                                   SkScalar currentVertex,
+                                   SkScalar prevVertex,
+                                   SkScalar stretchFactor) {
+    // the standard delta between vertices if no stretching is required
+    SkScalar delta = currentVertex - prevVertex;
+
+    // if the stretch factor is negative or zero we need to shrink the 9-patch
+    // to fit within the target bounds.  This means that we will eliminate all
+    // stretchy areas and scale the fixed areas to fit within the target bounds.
+    if (stretchFactor <= 0) {
+        if (isStretchyVertex)
+            delta = 0; // collapse stretchable areas
+        else
+            delta = SkScalarMul(delta, -stretchFactor); // scale fixed areas
+    // if the stretch factor is positive then we use the standard delta for
+    // fixed and scale the stretchable areas to fill the target bounds.
+    } else if (isStretchyVertex) {
+        delta = SkScalarMul(delta, stretchFactor);
+    }
+
+    return delta;
+}
+
 static void fillRow(SkPoint verts[], SkPoint texs[],
                     const SkScalar vy, const SkScalar ty,
                     const SkRect& bounds, const int32_t xDivs[], int numXDivs,
@@ -60,13 +85,14 @@
     SkScalar vx = bounds.fLeft;
     verts->set(vx, vy); verts++;
     texs->set(0, ty); texs++;
+
+    SkScalar prev = 0;
     for (int x = 0; x < numXDivs; x++) {
-        SkScalar tx = SkIntToScalar(xDivs[x]);
-        if (x & 1) {
-            vx += stretchX;
-        } else {
-            vx += tx;
-        }
+
+        const SkScalar tx = SkIntToScalar(xDivs[x]);
+        vx += computeVertexDelta(x & 1, tx, prev, stretchX);
+        prev = tx;
+
         verts->set(vx, vy); verts++;
         texs->set(tx, ty); texs++;
     }
@@ -117,8 +143,6 @@
     const int numYStretch = (numYDivs + 1) >> 1;
     
     if (numXStretch < 1 && numYStretch < 1) {
-    BITMAP_RECT:
-//        SkDebugf("------ drawasamesh revert to bitmaprect\n");
         canvas->drawBitmapRect(bitmap, NULL, bounds, paint);
         return;
     }
@@ -140,11 +164,11 @@
         for (int i = 1; i < numXDivs; i += 2) {
             stretchSize += xDivs[i] - xDivs[i-1];
         }
-        int fixed = bitmap.width() - stretchSize;
-        stretchX = (bounds.width() - SkIntToScalar(fixed)) / numXStretch;
-        if (stretchX < 0) {
-            goto BITMAP_RECT;
-        }
+        const SkScalar fixed = SkIntToScalar(bitmap.width() - stretchSize);
+        if (bounds.width() >= fixed)
+            stretchX = (bounds.width() - fixed) / stretchSize;
+        else // reuse stretchX, but keep it negative as a signal
+            stretchX = SkScalarDiv(-bounds.width(), fixed);
     }
     
     if (numYStretch > 0) {
@@ -152,11 +176,11 @@
         for (int i = 1; i < numYDivs; i += 2) {
             stretchSize += yDivs[i] - yDivs[i-1];
         }
-        int fixed = bitmap.height() - stretchSize;
-        stretchY = (bounds.height() - SkIntToScalar(fixed)) / numYStretch;
-        if (stretchY < 0) {
-            goto BITMAP_RECT;
-        }
+        const SkScalar fixed = SkIntToScalar(bitmap.height() - stretchSize);
+        if (bounds.height() >= fixed)
+            stretchY = (bounds.height() - fixed) / stretchSize;
+        else // reuse stretchX, but keep it negative as a signal
+            stretchY = SkScalarDiv(-bounds.height(), fixed);
     }
     
 #if 0
@@ -196,13 +220,13 @@
             stretchX, bitmap.width());
     verts += numXDivs + 2;
     texs += numXDivs + 2;
+
+    SkScalar prev = 0;
     for (int y = 0; y < numYDivs; y++) {
         const SkScalar ty = SkIntToScalar(yDivs[y]);
-        if (y & 1) {
-            vy += stretchY;
-        } else {
-            vy += ty;
-        }
+        vy += computeVertexDelta(y & 1, ty, prev, stretchY);
+        prev = ty;
+
         fillRow(verts, texs, vy, ty, bounds, xDivs, numXDivs,
                 stretchX, bitmap.width());
         verts += numXDivs + 2;