Skip to content

Commit

Permalink
fixed GifDrawable#getAllocationByteCount() to return value consiste…
Browse files Browse the repository at this point in the history
…nt with docs (taking optional dispose to previous into account)

added `GifDrawable#getMetadataByteCount()`, fixes #348
  • Loading branch information
koral-- committed Oct 9, 2016
1 parent 81117e4 commit 491b8b4
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 51 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- Build tools version updated to 24.0.3
- NDK version updated to 13
- native code optimizations
- fixed `GifDrawable#getAllocationByteCount()` to return value consistent with docs (taking optional dispose to previous into account)
- added `GifDrawable#getMetadataByteCount()` - [#348](https://github.com/koral--/android-gif-drawable/issues/348)

### 1.2.2
- Fixed NPE in `GifTexImage2D` finalizer when constructor threw an exception
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public void seekToFrame(@IntRange(from = 0, to = Integer.MAX_VALUE) final int fr
/**
* See {@link GifDrawable#getAllocationByteCount()}
*
* @return size of the allocated memory used to store pixels of this object
* @return possible size of the memory needed to store pixels of this object
*/
public long getAllocationByteCount() {
return mGifInfoHandle.getAllocationByteCount();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,21 +648,32 @@ public int getFrameByteCount() {
}

/**
* Returns size of the allocated memory used to store pixels of this object.
* It counts length of all frame buffers. Returned value does not change during runtime.
* Returns size of the memory needed to store pixels of this object. It counts possible length of all frame buffers.
* Returned value may be lower than amount of actually allocated memory if GIF uses dispose to previous method but frame requiring it
* has never been needed yet. Returned value does not change during runtime.
*
* @return size of the allocated memory used to store pixels of this object
* @return possible size of the memory needed to store pixels of this object
*/
public long getAllocationByteCount() {
long byteCount = mNativeInfoHandle.getAllocationByteCount();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
byteCount += mBuffer.getAllocationByteCount();
} else {
byteCount += mBuffer.getRowBytes() * mBuffer.getHeight();
byteCount += getFrameByteCount();
}
return byteCount;
}

/**
* Returns the maximum possible size of the allocated memory used to store pixels and metadata of this object.
* It counts length of all frame buffers. Returned value does not change over time.
*
* @return maximum possible size of the allocated memory used to store pixels and metadata of this object
*/
public long getMetadataAllocationByteCount() {
return mNativeInfoHandle.getMetadataByteCount();
}

/**
* Returns length of the input source obtained at the opening time or -1 if
* length cannot be determined. Returned value does not change during runtime.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ final class GifInfoHandle {
try {
gifInfoPtr = openFd(afd.getFileDescriptor(), afd.getStartOffset());
} finally {
afd.close();
try {
afd.close();
} catch (IOException ignored) {
//no-op
}
}
}

Expand Down Expand Up @@ -110,6 +114,8 @@ static GifInfoHandle openUri(ContentResolver resolver, Uri uri) throws IOExcepti

private static native long getAllocationByteCount(long gifFileInPtr);

private static native long getMetadataByteCount(long gifFileInPtr);

private static native int getNativeErrorCode(long gifFileInPtr);

private static native int getCurrentFrameIndex(long gifFileInPtr);
Expand Down Expand Up @@ -238,6 +244,10 @@ synchronized long getAllocationByteCount() {
return getAllocationByteCount(gifInfoPtr);
}

synchronized long getMetadataByteCount() {
return getMetadataByteCount(gifInfoPtr);
}

synchronized boolean isRecycled() {
return gifInfoPtr == 0L;
}
Expand Down
116 changes: 71 additions & 45 deletions android-gif-drawable/src/main/jni/metadata.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#include "gif.h"

__unused JNIEXPORT jstring JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getComment(JNIEnv *env, jclass __unused handleClass,
jlong gifInfo) {
if (gifInfo == 0) {
Java_pl_droidsonroids_gif_GifInfoHandle_getComment(JNIEnv *env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return NULL;
}
return (*env)->NewStringUTF(env, ((GifInfo *) (intptr_t) gifInfo)->comment);
return (*env)->NewStringUTF(env, info->comment);
}

__unused JNIEXPORT jboolean JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_isAnimationCompleted(JNIEnv __unused *env, jclass __unused handleClass,
jlong gifInfo) {
Java_pl_droidsonroids_gif_GifInfoHandle_isAnimationCompleted(JNIEnv __unused *env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *info = ((GifInfo *) (intptr_t) gifInfo);
if (info != NULL && info->loopCount != 0 && info->currentLoop == info->loopCount)
return JNI_TRUE;
Expand All @@ -20,27 +19,28 @@ Java_pl_droidsonroids_gif_GifInfoHandle_isAnimationCompleted(JNIEnv __unused *en
}

__unused JNIEXPORT jint JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getLoopCount(JNIEnv __unused *env, jclass __unused handleClass,
jlong gifInfo) {
if (gifInfo == 0)
Java_pl_droidsonroids_gif_GifInfoHandle_getLoopCount(JNIEnv __unused *env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return 0;
}
return (jint) ((GifInfo *) (intptr_t) gifInfo)->loopCount;
}

__unused JNIEXPORT void JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_setLoopCount(JNIEnv __unused *env, jclass __unused handleClass,
jlong gifInfo, jchar loopCount) {
if (gifInfo != 0)
((GifInfo *) (intptr_t) gifInfo)->loopCount = (uint_fast16_t) loopCount;
Java_pl_droidsonroids_gif_GifInfoHandle_setLoopCount(JNIEnv __unused *env, jclass __unused handleClass, jlong gifInfo, jchar loopCount) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info != NULL) {
info->loopCount = loopCount;
}
}

__unused JNIEXPORT jint JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getDuration(JNIEnv *__unused env, jclass __unused handleClass,
jlong gifInfo) {
if (gifInfo == 0) {
Java_pl_droidsonroids_gif_GifInfoHandle_getDuration(JNIEnv *__unused env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return 0;
}
GifInfo *info = (GifInfo *) (intptr_t) gifInfo;
uint_fast32_t i;
jint sum = 0;
for (i = 0; i < info->gifFilePtr->ImageCount; i++)
Expand All @@ -49,21 +49,20 @@ Java_pl_droidsonroids_gif_GifInfoHandle_getDuration(JNIEnv *__unused env, jclas
}

__unused JNIEXPORT jlong JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getSourceLength(JNIEnv __unused *env, jclass __unused handleClass,
jlong gifInfo) {
if (gifInfo == 0) {
Java_pl_droidsonroids_gif_GifInfoHandle_getSourceLength(JNIEnv __unused *env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return -1;
}
return ((GifInfo *) (intptr_t) gifInfo)->sourceLength;
}

__unused JNIEXPORT jint JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getCurrentPosition(JNIEnv *__unused env,
jclass __unused handleClass, jlong gifInfo) {
if (gifInfo == 0) {
Java_pl_droidsonroids_gif_GifInfoHandle_getCurrentPosition(JNIEnv *__unused env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return 0;
}
GifInfo *info = (GifInfo *) (intptr_t) gifInfo;
const uint_fast32_t idx = info->currentIndex;
if (info->gifFilePtr->ImageCount == 1) {
return 0;
Expand All @@ -88,49 +87,76 @@ Java_pl_droidsonroids_gif_GifInfoHandle_getCurrentPosition(JNIEnv *__unused env,
}

__unused JNIEXPORT jlong JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getAllocationByteCount(JNIEnv *__unused env,
jclass __unused handleClass, jlong gifInfo) {
if (gifInfo == 0) {
Java_pl_droidsonroids_gif_GifInfoHandle_getMetadataByteCount(JNIEnv *__unused env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return 0;
}

size_t size = sizeof(GifInfo) + sizeof(GifFileType);
size += info->gifFilePtr->ImageCount * (sizeof(GraphicsControlBlock) + sizeof(SavedImage));
size += info->comment != NULL ? strlen(info->comment) : 0;
return (jlong) size;
}

__unused JNIEXPORT jlong JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getAllocationByteCount(JNIEnv *__unused env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return 0;
}
GifInfo *info = (GifInfo *) (intptr_t) gifInfo;
GifWord pxCount = info->originalWidth + info->originalHeight;
size_t sum = pxCount * sizeof(char);
if (info->backupPtr != NULL)
sum += pxCount * sizeof(argb);
return (jlong) sum;

bool isBackupBitmapUsed = info->backupPtr != NULL;
if (!isBackupBitmapUsed) {
uint_fast32_t i;
for (i = 1; i < info->gifFilePtr->ImageCount; i++) {
if (info->controlBlock[i].DisposalMode == DISPOSE_PREVIOUS) {
isBackupBitmapUsed = true;
break;
}
}
}

size_t size = info->rasterSize * sizeof(GifPixelType);
if (isBackupBitmapUsed) {
size += info->stride * info->gifFilePtr->SHeight * sizeof(argb);
}
return (jlong) size;
}

__unused JNIEXPORT jint JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getNativeErrorCode(JNIEnv *__unused env,
jclass __unused handleClass, jlong gifInfo) {
if (gifInfo == 0)
Java_pl_droidsonroids_gif_GifInfoHandle_getNativeErrorCode(JNIEnv *__unused env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return 0;
}
return ((GifInfo *) (intptr_t) gifInfo)->gifFilePtr->Error;
}

__unused JNIEXPORT jint JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getCurrentLoop(JNIEnv __unused *env, jclass __unused handleClass,
jlong gifInfo) {
if (gifInfo == 0)
Java_pl_droidsonroids_gif_GifInfoHandle_getCurrentLoop(JNIEnv __unused *env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return 0;
}
return (jint) ((GifInfo *) (intptr_t) gifInfo)->currentLoop;
}

__unused JNIEXPORT jint JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getCurrentFrameIndex(JNIEnv __unused *env, jclass __unused handleClass,
jlong gifInfo) {
if (gifInfo == 0)
Java_pl_droidsonroids_gif_GifInfoHandle_getCurrentFrameIndex(JNIEnv __unused *env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL) {
return -1;
}
return (jint) ((GifInfo *) (intptr_t) gifInfo)->currentIndex;
}

__unused JNIEXPORT jlongArray JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_getSavedState(JNIEnv *env, jclass __unused handleClass,
jlong gifInfo) {
Java_pl_droidsonroids_gif_GifInfoHandle_getSavedState(JNIEnv *env, jclass __unused handleClass, jlong gifInfo) {
GifInfo *const info = ((GifInfo *) (intptr_t) gifInfo);
if (info == NULL)
if (info == NULL) {
return NULL;
}

const jlongArray state = (*env)->NewLongArray(env, 4);
if (state == NULL) {
Expand Down

0 comments on commit 491b8b4

Please sign in to comment.