diff options
author | Chris Craik <ccraik@google.com> | 2014-08-20 16:31:57 -0700 |
---|---|---|
committer | Chris Craik <ccraik@google.com> | 2014-08-20 16:37:16 -0700 |
commit | bd8db2e87e16900ff9b87937d3ccff6a50bd5b2a (patch) | |
tree | b9570ed468f411e794457427882b2c6214136fa9 /core/jni/android | |
parent | 3acf66f5580b9e411ff20674c676de0901d4b459 (diff) | |
download | frameworks_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/android')
-rw-r--r-- | core/jni/android/graphics/BitmapFactory.cpp | 47 |
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(); |