Implement getTransparentRegion() using SkLatticeIter

This allows us to delete utils/NinePatchImpl.cpp and
utils/NinePatch.h

Test: Passed cts tests - DrawableTest, NinePatchTest,
NinePatchDrawableTest.

Change-Id: I6b5d09fa3479e758d8b931fa0e977c25f4435a7c
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 0aa7808..719b115 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -38,7 +38,6 @@
     utils/Blur.cpp \
     utils/GLUtils.cpp \
     utils/LinearAllocator.cpp \
-    utils/NinePatchImpl.cpp \
     utils/StringUtils.cpp \
     utils/TestWindowContext.cpp \
     utils/VectorDrawableUtils.cpp \
diff --git a/libs/hwui/NinePatchUtils.h b/libs/hwui/NinePatchUtils.h
new file mode 100644
index 0000000..7a271b7
--- /dev/null
+++ b/libs/hwui/NinePatchUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace android {
+namespace NinePatchUtils {
+
+static inline void SetLatticeDivs(SkCanvas::Lattice* lattice, const Res_png_9patch& chunk,
+        int width, int height) {
+    lattice->fXCount = chunk.numXDivs;
+    lattice->fYCount = chunk.numYDivs;
+    lattice->fXDivs = chunk.getXDivs();
+    lattice->fYDivs = chunk.getYDivs();
+
+    // We'll often see ninepatches where the last div is equal to the width or height.
+    // This doesn't provide any additional information and is not supported by Skia.
+    if (lattice->fXCount > 0 && width == lattice->fXDivs[lattice->fXCount - 1]) {
+        lattice->fXCount--;
+    }
+    if (lattice->fYCount > 0 && height == lattice->fYDivs[lattice->fYCount - 1]) {
+        lattice->fYCount--;
+    }
+}
+
+}; // namespace NinePatchUtils
+}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index a8fcfeb..b6031c4 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -26,7 +26,6 @@
 #include "hwui/Canvas.h"
 #include "utils/LinearAllocator.h"
 #include "utils/Macros.h"
-#include "utils/NinePatch.h"
 
 #include <SkDrawFilter.h>
 #include <SkPaint.h>
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 11aaebd..c48b4dc 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -17,6 +17,7 @@
 #include "SkiaCanvas.h"
 
 #include "CanvasProperty.h"
+#include "NinePatchUtils.h"
 #include "VectorDrawable.h"
 #include "hwui/Bitmap.h"
 #include "hwui/MinikinUtils.h"
@@ -670,23 +671,6 @@
                          indexCount, tmpPaint);
 }
 
-static inline void set_lattice_divs(SkCanvas::Lattice* lattice, const Res_png_9patch& chunk,
-                                    int width, int height) {
-    lattice->fXCount = chunk.numXDivs;
-    lattice->fYCount = chunk.numYDivs;
-    lattice->fXDivs = chunk.getXDivs();
-    lattice->fYDivs = chunk.getYDivs();
-
-    // We'll often see ninepatches where the last div is equal to the width or height.
-    // This doesn't provide any additional information and is not supported by Skia.
-    if (lattice->fXCount > 0 && width == lattice->fXDivs[lattice->fXCount - 1]) {
-        lattice->fXCount--;
-    }
-    if (lattice->fYCount > 0 && height == lattice->fYDivs[lattice->fYCount - 1]) {
-        lattice->fYCount--;
-    }
-}
-
 static inline int num_distinct_rects(const SkCanvas::Lattice& lattice) {
     int xRects;
     if (lattice.fXCount > 0) {
@@ -750,7 +734,7 @@
     hwuiBitmap.getSkBitmap(&bitmap);
 
     SkCanvas::Lattice lattice;
-    set_lattice_divs(&lattice, chunk, bitmap.width(), bitmap.height());
+    NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
 
     lattice.fFlags = nullptr;
     int numFlags = 0;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index f275ce1..d7839b4 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -21,7 +21,7 @@
 
 #include "GlFunctorLifecycleListener.h"
 #include "utils/Macros.h"
-#include "utils/NinePatch.h"
+#include <androidfw/ResourceTypes.h>
 
 #include <SkBitmap.h>
 #include <SkCanvas.h>
diff --git a/libs/hwui/utils/NinePatch.h b/libs/hwui/utils/NinePatch.h
deleted file mode 100644
index 323e563..0000000
--- a/libs/hwui/utils/NinePatch.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_GRAPHICS_NINEPATCH_H
-#define ANDROID_GRAPHICS_NINEPATCH_H
-
-#include <androidfw/ResourceTypes.h>
-#include <cutils/compiler.h>
-
-#include "SkCanvas.h"
-#include "SkRegion.h"
-
-namespace android {
-
-class ANDROID_API NinePatch {
-public:
-    static void Draw(SkCanvas* canvas, const SkRect& bounds, const SkBitmap& bitmap,
-            const Res_png_9patch& chunk, const SkPaint* paint, SkRegion** outRegion);
-};
-
-} // namespace android
-
-#endif // ANDROID_GRAPHICS_NINEPATCH_H
diff --git a/libs/hwui/utils/NinePatchImpl.cpp b/libs/hwui/utils/NinePatchImpl.cpp
deleted file mode 100644
index cef214b..0000000
--- a/libs/hwui/utils/NinePatchImpl.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include "utils/NinePatch.h"
-
-#include "SkBitmap.h"
-#include "SkCanvas.h"
-#include "SkColorPriv.h"
-#include "SkPaint.h"
-#include "SkUnPreMultiply.h"
-
-#include <utils/Log.h>
-
-namespace android {
-
-static const bool kUseTrace = true;
-static bool gTrace = false;
-
-static bool getColor(const SkBitmap& bitmap, int x, int y, SkColor* c) {
-    switch (bitmap.colorType()) {
-        case kN32_SkColorType:
-            *c = SkUnPreMultiply::PMColorToColor(*bitmap.getAddr32(x, y));
-            break;
-        case kRGB_565_SkColorType:
-            *c = SkPixel16ToPixel32(*bitmap.getAddr16(x, y));
-            break;
-        case kARGB_4444_SkColorType:
-            *c = SkUnPreMultiply::PMColorToColor(
-                                SkPixel4444ToPixel32(*bitmap.getAddr16(x, y)));
-            break;
-        case kIndex_8_SkColorType: {
-            SkColorTable* ctable = bitmap.getColorTable();
-            *c = SkUnPreMultiply::PMColorToColor(
-                                            (*ctable)[*bitmap.getAddr8(x, y)]);
-            break;
-        }
-        default:
-            return false;
-    }
-    return true;
-}
-
-static SkColor modAlpha(SkColor c, int alpha) {
-    int scale = alpha + (alpha >> 7);
-    int a = SkColorGetA(c) * scale >> 8;
-    return SkColorSetA(c, a);
-}
-
-static void drawStretchyPatch(SkCanvas* canvas, SkIRect& src, const SkRect& dst,
-                              const SkBitmap& bitmap, const SkPaint& paint,
-                              SkColor initColor, uint32_t colorHint,
-                              bool hasXfer) {
-    if (colorHint !=  android::Res_png_9patch::NO_COLOR) {
-        ((SkPaint*)&paint)->setColor(modAlpha(colorHint, paint.getAlpha()));
-        canvas->drawRect(dst, paint);
-        ((SkPaint*)&paint)->setColor(initColor);
-    } else if (src.width() == 1 && src.height() == 1) {
-        SkColor c;
-        if (!getColor(bitmap, src.fLeft, src.fTop, &c)) {
-            goto SLOW_CASE;
-        }
-        if (0 != c || hasXfer) {
-            SkColor prev = paint.getColor();
-            ((SkPaint*)&paint)->setColor(c);
-            canvas->drawRect(dst, paint);
-            ((SkPaint*)&paint)->setColor(prev);
-        }
-    } else {
-    SLOW_CASE:
-        canvas->drawBitmapRect(bitmap, SkRect::Make(src), dst, &paint);
-    }
-}
-
-SkScalar calculateStretch(SkScalar boundsLimit, SkScalar startingPoint,
-                          int srcSpace, int numStrechyPixelsRemaining,
-                          int numFixedPixelsRemaining) {
-    SkScalar spaceRemaining = boundsLimit - startingPoint;
-    SkScalar stretchySpaceRemaining =
-                spaceRemaining - SkIntToScalar(numFixedPixelsRemaining);
-    return srcSpace * stretchySpaceRemaining / numStrechyPixelsRemaining;
-}
-
-void NinePatch::Draw(SkCanvas* canvas, const SkRect& bounds,
-                     const SkBitmap& bitmap, const Res_png_9patch& chunk,
-                     const SkPaint* paint, SkRegion** outRegion) {
-    if (canvas && canvas->quickReject(bounds)) {
-        return;
-    }
-
-    SkPaint defaultPaint;
-    if (NULL == paint) {
-        // matches default dither in NinePatchDrawable.java.
-        defaultPaint.setDither(true);
-        paint = &defaultPaint;
-    }
-   
-    const int32_t* xDivs = chunk.getXDivs();
-    const int32_t* yDivs = chunk.getYDivs();
-
-    if (kUseTrace) {
-        gTrace = true;
-    }
-
-    SkASSERT(canvas || outRegion);
-
-    if (kUseTrace) {
-        if (canvas) {
-            const SkMatrix& m = canvas->getTotalMatrix();
-            ALOGV("ninepatch [%g %g %g] [%g %g %g]\n",
-                    SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
-                    SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
-        }
-
-        ALOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()),
-                SkScalarToFloat(bounds.height()));
-        ALOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height());
-        ALOGV("======== ninepatch xDivs [%d,%d]\n", xDivs[0], xDivs[1]);
-        ALOGV("======== ninepatch yDivs [%d,%d]\n", yDivs[0], yDivs[1]);
-    }
-
-    if (bounds.isEmpty() ||
-        bitmap.width() == 0 || bitmap.height() == 0 ||
-        (paint && paint->isSrcOver() && paint->getAlpha() == 0))
-    {
-        if (kUseTrace) {
-            ALOGV("======== abort ninepatch draw\n");
-        }
-        return;
-    }
-    
-    // should try a quick-reject test before calling lockPixels 
-
-    SkAutoLockPixels alp(bitmap);
-    // after the lock, it is valid to check getPixels()
-    if (bitmap.getPixels() == NULL)
-        return;
-
-    const bool hasXfer = !paint->isSrcOver();
-    SkRect      dst;
-    SkIRect     src;
-
-    const int32_t x0 = xDivs[0];
-    const int32_t y0 = yDivs[0];
-    const SkColor initColor = ((SkPaint*)paint)->getColor();
-    const uint8_t numXDivs = chunk.numXDivs;
-    const uint8_t numYDivs = chunk.numYDivs;
-    int i;
-    int j;
-    int colorIndex = 0;
-    uint32_t color;
-    bool xIsStretchable;
-    const bool initialXIsStretchable =  (x0 == 0);
-    bool yIsStretchable = (y0 == 0);
-    const int bitmapWidth = bitmap.width();
-    const int bitmapHeight = bitmap.height();
-
-    // Number of bytes needed for dstRights array.
-    // Need to cast numXDivs to a larger type to avoid overflow.
-    const size_t dstBytes = ((size_t) numXDivs + 1) * sizeof(SkScalar);
-    SkScalar* dstRights = (SkScalar*) alloca(dstBytes);
-    bool dstRightsHaveBeenCached = false;
-
-    int numStretchyXPixelsRemaining = 0;
-    for (i = 0; i < numXDivs; i += 2) {
-        numStretchyXPixelsRemaining += xDivs[i + 1] - xDivs[i];
-    }
-    int numFixedXPixelsRemaining = bitmapWidth - numStretchyXPixelsRemaining;
-    int numStretchyYPixelsRemaining = 0;
-    for (i = 0; i < numYDivs; i += 2) {
-        numStretchyYPixelsRemaining += yDivs[i + 1] - yDivs[i];
-    }
-    int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining;
-
-    if (kUseTrace) {
-        ALOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
-                bitmap.width(), bitmap.height(),
-                SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
-                SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
-                numXDivs, numYDivs);
-    }
-
-    src.fTop = 0;
-    dst.fTop = bounds.fTop;
-    // The first row always starts with the top being at y=0 and the bottom
-    // being either yDivs[1] (if yDivs[0]=0) or yDivs[0].  In the former case
-    // the first row is stretchable along the Y axis, otherwise it is fixed.
-    // The last row always ends with the bottom being bitmap.height and the top
-    // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or
-    // yDivs[numYDivs-1]. In the former case the last row is stretchable along
-    // the Y axis, otherwise it is fixed.
-    //
-    // The first and last columns are similarly treated with respect to the X
-    // axis.
-    //
-    // The above is to help explain some of the special casing that goes on the
-    // code below.
-
-    // The initial yDiv and whether the first row is considered stretchable or
-    // not depends on whether yDiv[0] was zero or not.
-    for (j = yIsStretchable ? 1 : 0;
-          j <= numYDivs && src.fTop < bitmapHeight;
-          j++, yIsStretchable = !yIsStretchable) {
-        src.fLeft = 0;
-        dst.fLeft = bounds.fLeft;
-        if (j == numYDivs) {
-            src.fBottom = bitmapHeight;
-            dst.fBottom = bounds.fBottom;
-        } else {
-            src.fBottom = yDivs[j];
-            const int srcYSize = src.fBottom - src.fTop;
-            if (yIsStretchable) {
-                dst.fBottom = dst.fTop + calculateStretch(bounds.fBottom, dst.fTop,
-                                                          srcYSize,
-                                                          numStretchyYPixelsRemaining,
-                                                          numFixedYPixelsRemaining);
-                numStretchyYPixelsRemaining -= srcYSize;
-            } else {
-                dst.fBottom = dst.fTop + SkIntToScalar(srcYSize);
-                numFixedYPixelsRemaining -= srcYSize;
-            }
-        }
-
-        xIsStretchable = initialXIsStretchable;
-        // The initial xDiv and whether the first column is considered
-        // stretchable or not depends on whether xDiv[0] was zero or not.
-        const uint32_t* colors = chunk.getColors();
-        for (i = xIsStretchable ? 1 : 0;
-              i <= numXDivs && src.fLeft < bitmapWidth;
-              i++, xIsStretchable = !xIsStretchable) {
-            color = colors[colorIndex++];
-            if (i == numXDivs) {
-                src.fRight = bitmapWidth;
-                dst.fRight = bounds.fRight;
-            } else {
-                src.fRight = xDivs[i];
-                if (dstRightsHaveBeenCached) {
-                    dst.fRight = dstRights[i];
-                } else {
-                    const int srcXSize = src.fRight - src.fLeft;
-                    if (xIsStretchable) {
-                        dst.fRight = dst.fLeft + calculateStretch(bounds.fRight, dst.fLeft,
-                                                                  srcXSize,
-                                                                  numStretchyXPixelsRemaining,
-                                                                  numFixedXPixelsRemaining);
-                        numStretchyXPixelsRemaining -= srcXSize;
-                    } else {
-                        dst.fRight = dst.fLeft + SkIntToScalar(srcXSize);
-                        numFixedXPixelsRemaining -= srcXSize;
-                    }
-                    dstRights[i] = dst.fRight;
-                }
-            }
-            // If this horizontal patch is too small to be displayed, leave
-            // the destination left edge where it is and go on to the next patch
-            // in the source.
-            if (src.fLeft >= src.fRight) {
-                src.fLeft = src.fRight;
-                continue;
-            }
-            // Make sure that we actually have room to draw any bits
-            if (dst.fRight <= dst.fLeft || dst.fBottom <= dst.fTop) {
-                goto nextDiv;
-            }
-            // If this patch is transparent, skip and don't draw.
-            if (color == android::Res_png_9patch::TRANSPARENT_COLOR && !hasXfer) {
-                if (outRegion) {
-                    if (*outRegion == NULL) {
-                        *outRegion = new SkRegion();
-                    }
-                    SkIRect idst;
-                    dst.round(&idst);
-                    //ALOGI("Adding trans rect: (%d,%d)-(%d,%d)\n",
-                    //     idst.fLeft, idst.fTop, idst.fRight, idst.fBottom);
-                    (*outRegion)->op(idst, SkRegion::kUnion_Op);
-                }
-                goto nextDiv;
-            }
-            if (canvas) {
-                if (kUseTrace) {
-                    ALOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
-                            src.fLeft, src.fTop, src.width(), src.height(),
-                            SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
-                            SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
-                    if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
-                        ALOGV("--- skip patch\n");
-                    }
-                }
-                drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor,
-                                  color, hasXfer);
-            }
-
-nextDiv:
-            src.fLeft = src.fRight;
-            dst.fLeft = dst.fRight;
-        }
-        src.fTop = src.fBottom;
-        dst.fTop = dst.fBottom;
-        dstRightsHaveBeenCached = true;
-    }
-}
-
-} // namespace android