diff options
author | Chris Craik <ccraik@google.com> | 2014-08-21 00:29:13 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-08-21 00:16:54 +0000 |
commit | 2d84cdb414fe15fb8d12a870e76b1e9cfdb2e10b (patch) | |
tree | 9d7807f7b31937b43c07bc2ba4aed8ec3b5e093a /core/jni | |
parent | 827296b7dd6689c14df1340f21a85e1f2f8d6844 (diff) | |
parent | bd8db2e87e16900ff9b87937d3ccff6a50bd5b2a (diff) | |
download | frameworks_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.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(); |