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