summaryrefslogtreecommitdiffstats
path: root/core/jni
diff options
context:
space:
mode:
authorChris Craik <ccraik@google.com>2014-08-20 16:31:57 -0700
committerChris Craik <ccraik@google.com>2014-08-20 16:37:16 -0700
commitbd8db2e87e16900ff9b87937d3ccff6a50bd5b2a (patch)
treeb9570ed468f411e794457427882b2c6214136fa9 /core/jni
parent3acf66f5580b9e411ff20674c676de0901d4b459 (diff)
downloadframeworks_base-bd8db2e87e16900ff9b87937d3ccff6a50bd5b2a.zip
frameworks_base-bd8db2e87e16900ff9b87937d3ccff6a50bd5b2a.tar.gz
frameworks_base-bd8db2e87e16900ff9b87937d3ccff6a50bd5b2a.tar.bz2
Add bounds checking to nine patch scaling
bug:17114103 Better handle the case, when scaling the divs in a nine patch, where divs fall outside of the bounds of the bitmap. Change-Id: I244b9c45b938c2a15f29e4563a86825ee9439b5f
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();