summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
authorChris Craik <ccraik@google.com>2014-08-21 00:29:13 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-08-21 00:16:54 +0000
commit2d84cdb414fe15fb8d12a870e76b1e9cfdb2e10b (patch)
tree9d7807f7b31937b43c07bc2ba4aed8ec3b5e093a /core/jni
parent827296b7dd6689c14df1340f21a85e1f2f8d6844 (diff)
parentbd8db2e87e16900ff9b87937d3ccff6a50bd5b2a (diff)
downloadframeworks_base-2d84cdb414fe15fb8d12a870e76b1e9cfdb2e10b.zip
frameworks_base-2d84cdb414fe15fb8d12a870e76b1e9cfdb2e10b.tar.gz
frameworks_base-2d84cdb414fe15fb8d12a870e76b1e9cfdb2e10b.tar.bz2
Merge "Add bounds checking to nine patch scaling" into lmp-dev
Diffstat (limited to 'core/jni')
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp47
1 files changed, 30 insertions, 17 deletions
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 2ce1b15..62ea351 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -18,6 +18,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <androidfw/Asset.h>
#include <androidfw/ResourceTypes.h>
+#include <cutils/compiler.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/mman.h>
@@ -87,29 +88,41 @@ static bool optionsJustBounds(JNIEnv* env, jobject options) {
return options != NULL && env->GetBooleanField(options, gOptions_justBoundsFieldID);
}
-static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale) {
- chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
- chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
- chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
- chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
-
- int32_t* xDivs = chunk->getXDivs();
- for (int i = 0; i < chunk->numXDivs; i++) {
- xDivs[i] = int32_t(xDivs[i] * scale + 0.5f);
- if (i > 0 && xDivs[i] == xDivs[i - 1]) {
- xDivs[i]++;
+static void scaleDivRange(int32_t* divs, int count, float scale, int maxValue) {
+ for (int i = 0; i < count; i++) {
+ divs[i] = int32_t(divs[i] * scale + 0.5f);
+ if (i > 0 && divs[i] == divs[i - 1]) {
+ divs[i]++; // avoid collisions
}
}
- int32_t* yDivs = chunk->getYDivs();
- for (int i = 0; i < chunk->numYDivs; i++) {
- yDivs[i] = int32_t(yDivs[i] * scale + 0.5f);
- if (i > 0 && yDivs[i] == yDivs[i - 1]) {
- yDivs[i]++;
+ if (CC_UNLIKELY(divs[count - 1] > maxValue)) {
+ // if the collision avoidance above put some divs outside the bounds of the bitmap,
+ // slide outer stretchable divs inward to stay within bounds
+ int highestAvailable = maxValue;
+ for (int i = count - 1; i >= 0; i--) {
+ divs[i] = highestAvailable;
+ if (i > 0 && divs[i] <= divs[i-1]){
+ // keep shifting
+ highestAvailable = divs[i] - 1;
+ } else {
+ break;
+ }
}
}
}
+static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale,
+ int scaledWidth, int scaledHeight) {
+ chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
+ chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
+ chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
+ chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
+
+ scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth);
+ scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight);
+}
+
static SkColorType colorTypeForScaledOutput(SkColorType colorType) {
switch (colorType) {
case kUnknown_SkColorType:
@@ -330,7 +343,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
jbyteArray ninePatchChunk = NULL;
if (peeker.mPatch != NULL) {
if (willScale) {
- scaleNinePatchChunk(peeker.mPatch, scale);
+ scaleNinePatchChunk(peeker.mPatch, scale, scaledWidth, scaledHeight);
}
size_t ninePatchArraySize = peeker.mPatch->serializedSize();