Skip to content

Commit

Permalink
opacity support for gifTextureView added
Browse files Browse the repository at this point in the history
  • Loading branch information
koral-- committed Apr 13, 2015
1 parent e0d9b27 commit b61da4a
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 22 deletions.
6 changes: 3 additions & 3 deletions src/main/java/pl/droidsonroids/gif/GifInfoHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private GifInfoHandle(long gifInfoPtr, int width, int height, int frameCount) {
static native GifInfoHandle openStream(InputStream stream, boolean justDecodeMetaData) throws GifIOException;
static native GifInfoHandle openFile(String filePath, boolean justDecodeMetaData) throws GifIOException;
private static native long renderFrame(long gifFileInPtr, Bitmap frameBuffer);
private static native void bindSurface(long gifInfoPtr, Surface surface, long[] savedState);
private static native void bindSurface(long gifInfoPtr, Surface surface, long[] savedState, boolean isOpaque, boolean wasOpaque);
private static native void free(long gifFileInPtr);
private static native boolean reset(long gifFileInPtr);
private static native void setSpeedFactor(long gifFileInPtr, float factor);
Expand Down Expand Up @@ -94,8 +94,8 @@ synchronized long renderFrame(Bitmap frameBuffer) {
return renderFrame(gifInfoPtr, frameBuffer);
}

void bindSurface(Surface surface, long[] savedState) {
bindSurface(gifInfoPtr, surface, savedState);
void bindSurface(Surface surface, long[] savedState, boolean isOpaque, boolean wasOpaque) {
bindSurface(gifInfoPtr, surface, savedState, isOpaque, wasOpaque);
}

synchronized void recycle() {
Expand Down
25 changes: 23 additions & 2 deletions src/main/java/pl/droidsonroids/gif/GifTextureView.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class GifTextureView extends TextureView {

private RenderThread mRenderThread;
private float mSpeedFactor = 1f;
private boolean mWasOpaque;

public GifTextureView(Context context) {
super(context);
Expand Down Expand Up @@ -80,7 +81,8 @@ private void init(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
}
final TypedArray textureViewAttributes = getContext().obtainStyledAttributes(attrs, R.styleable.GifTextureView, defStyleAttr, defStyleRes);
mInputSource = findSource(textureViewAttributes);
setOpaque(textureViewAttributes.getBoolean(R.styleable.GifTextureView_isOpaque, false));
mWasOpaque = textureViewAttributes.getBoolean(R.styleable.GifTextureView_isOpaque, false);
setOpaque(mWasOpaque);
textureViewAttributes.recycle();
mFreezesAnimation = GifViewUtils.isFreezingAnimation(this, attrs, defStyleAttr, defStyleRes);
mRenderThread = new RenderThread();
Expand Down Expand Up @@ -181,7 +183,7 @@ public void run() {
}
final Surface surface = new Surface(surfaceTexture);
try {
mGifInfoHandle.bindSurface(surface, mSavedState);
mGifInfoHandle.bindSurface(surface, mSavedState, isOpaque(), mWasOpaque);
} finally {
surface.release();
}
Expand Down Expand Up @@ -231,6 +233,24 @@ void dispose() {
}
}

/**
* Indicates whether the content of this GifTextureView is opaque. The
* content is assumed to be <b>non-opaque</b> by default (unlike {@link TextureView}.
* View that is known to be opaque can take a faster drawing case than non-opaque one.<br>
* If opacity is changed from true to false then pending animation will be restarted.
*
* @param opaque True if the content of this GifTextureView is opaque,
* false otherwise
*/
@Override
public void setOpaque(final boolean opaque) {
mWasOpaque = isOpaque();
if (mWasOpaque != opaque) {
super.setOpaque(opaque);
mRenderThread.mGifInfoHandle.postUnbindSurface();
}
}

@Override
protected void onDetachedFromWindow() {
mRenderThread.dispose();
Expand All @@ -251,6 +271,7 @@ public synchronized void setInputSource(@Nullable InputSource inputSource) {
mInputSource = inputSource;
mRenderThread = new RenderThread();
if (inputSource != null) {
setOpaque(inputSource.isOpaque());
mRenderThread.start();
}
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/pl/droidsonroids/gif/InputSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
* Abstract class for all input sources, to be used with {@link GifTextureView}
*/
public abstract class InputSource {
private boolean mIsOpaque;

InputSource() {
}

Expand All @@ -30,6 +32,23 @@ final GifDrawable build(GifDrawable oldDrawable, ScheduledThreadPoolExecutor exe
return new GifDrawable(open(), oldDrawable, executor, isRenderingAlwaysEnabled);
}

final boolean isOpaque() {
return mIsOpaque;
}

/**
* Indicates whether the content of this source is opaque. GIF that is known to be opaque can
* take a faster drawing case than non-opaque one. See {@link GifTextureView#setOpaque(boolean)}
* for more information.<br>
* Currently it is used only by {@link GifTextureView}, not by {@link GifDrawable}
* @param isOpaque whether the content of this source is opaque
* @return this InputSource
*/
public final InputSource setOpaque(boolean isOpaque) {
mIsOpaque = isOpaque;
return this;
}

/**
* Input using {@link ByteBuffer} as a source. It must be direct.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main/jni/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Java_pl_droidsonroids_gif_GifInfoHandle_renderFrame(JNIEnv *env, jclass __unused
return 0;
}
DDGifSlurp(info, true);
const uint_fast16_t frameDuration = getBitmap((argb *) pixels, info);
const uint_fast32_t frameDuration = getBitmap((argb *) pixels, info);
unlockPixels(env, jbitmap);
return calculateInvalidationDelay(info, renderStartTime, frameDuration);
}
44 changes: 32 additions & 12 deletions src/main/jni/drawing.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,43 @@ static void blitNormal(argb *bm, GifInfo *info, SavedImage *frame, ColorMapObjec

uint_fast16_t x, y = frame->ImageDesc.Height;
const int_fast16_t transpIndex = info->infos[info->currentIndex].TransparentColor;
if (transpIndex == NO_TRANSPARENT_COLOR) {
for (; y > 0; y--) {
MEMSET_ARGB((uint32_t *) dst, UINT32_MAX, frame->ImageDesc.Width);
for (x = frame->ImageDesc.Width; x > 0; x--, src++, dst++)
dst->rgb = cmap->Colors[*src];
dst += info->stride - frame->ImageDesc.Width;
if (info->isOpaque == JNI_TRUE) {
if (transpIndex == NO_TRANSPARENT_COLOR) {
for (; y > 0; y--) {
for (x = frame->ImageDesc.Width; x > 0; x--, src++, dst++)
dst->rgb = cmap->Colors[*src];
dst += info->stride - frame->ImageDesc.Width;
}
}
else {
for (; y > 0; y--) {
for (x = frame->ImageDesc.Width; x > 0; x--, src++, dst++) {
if (*src != transpIndex)
dst->rgb = cmap->Colors[*src];
}
dst += info->stride - frame->ImageDesc.Width;
}
}
}
else {
for (; y > 0; y--) {
for (x = frame->ImageDesc.Width; x > 0; x--, src++, dst++) {
if (*src != transpIndex) {
if (transpIndex == NO_TRANSPARENT_COLOR) {
for (; y > 0; y--) {
MEMSET_ARGB((uint32_t *) dst, UINT32_MAX, frame->ImageDesc.Width);
for (x = frame->ImageDesc.Width; x > 0; x--, src++, dst++)
dst->rgb = cmap->Colors[*src];
dst->alpha = 0xFF;
dst += info->stride - frame->ImageDesc.Width;
}
}
else {
for (; y > 0; y--) {
for (x = frame->ImageDesc.Width; x > 0; x--, src++, dst++) {
if (*src != transpIndex) {
dst->rgb = cmap->Colors[*src];
dst->alpha = 0xFF;
}
}
dst += info->stride - frame->ImageDesc.Width;
}
dst += info->stride - frame->ImageDesc.Width;
}
}
}
Expand Down Expand Up @@ -115,7 +135,7 @@ static inline void disposeFrameIfNeeded(argb *bm, GifInfo *info, int idx) {
memcpy(backup, bm, info->stride * fGif->SHeight * sizeof(argb));
}

uint_fast16_t const getBitmap(argb *bm, GifInfo *info) {
uint_fast32_t const getBitmap(argb *bm, GifInfo *info) {
if (info->currentIndex == 0) {
if (info->gifFilePtr->SColorMap && info->infos[0].TransparentColor == NO_TRANSPARENT_COLOR) {
argb bgColArgb;
Expand Down
1 change: 1 addition & 0 deletions src/main/jni/gif.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ struct GifInfo {
jlong sourceLength;
int eventFd;
void *surfaceBackupPtr;
jboolean isOpaque;
};

typedef struct {
Expand Down
1 change: 1 addition & 0 deletions src/main/jni/open_close.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jobject createGifHandle(GifSourceDescriptor *descriptor, JNIEnv *env, jboolean j
info->rewindFunction = descriptor->rewindFunc;
info->eventFd = -1;
info->surfaceBackupPtr = NULL;
info->isOpaque = JNI_FALSE;

DDGifSlurp(info, false);
if (justDecodeMetaData == JNI_TRUE)
Expand Down
17 changes: 13 additions & 4 deletions src/main/jni/surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ typedef uint64_t POLL_TYPE;

__unused JNIEXPORT void JNICALL
Java_pl_droidsonroids_gif_GifInfoHandle_bindSurface(JNIEnv *env, jclass __unused handleClass,
jlong gifInfo, jobject jsurface, jlongArray savedState) {
jlong gifInfo, jobject jsurface, jlongArray savedState,
jboolean isOpaque, jboolean wasOpaque) {

GifInfo *info = (GifInfo *) (intptr_t) gifInfo;

Expand All @@ -18,9 +19,11 @@ Java_pl_droidsonroids_gif_GifInfoHandle_bindSurface(JNIEnv *env, jclass __unused
return;
}
}
info->isOpaque = isOpaque;
struct ANativeWindow *window = ANativeWindow_fromSurface(env, jsurface);
const int32_t windowFormat = isOpaque == JNI_TRUE ? WINDOW_FORMAT_RGBX_8888 : WINDOW_FORMAT_RGBA_8888;
if (ANativeWindow_setBuffersGeometry(window, info->gifFilePtr->SWidth, info->gifFilePtr->SHeight,
WINDOW_FORMAT_RGBA_8888) != 0) {
windowFormat) != 0) {
ANativeWindow_release(window);
throwException(env, ILLEGAL_STATE_EXCEPTION_ERRNO, "Buffers geometry setting failed");
return;
Expand Down Expand Up @@ -57,7 +60,13 @@ Java_pl_droidsonroids_gif_GifInfoHandle_bindSurface(JNIEnv *env, jclass __unused
const size_t bufferSize = buffer.stride * buffer.height * sizeof(argb);

info->stride = buffer.stride;
if (info->surfaceBackupPtr) {
if (isOpaque == JNI_FALSE && wasOpaque == JNI_TRUE) {
if (!reset(info)) {
ANativeWindow_release(window);
return;
}
}
else if (info->surfaceBackupPtr) {
memcpy(buffer.bits, info->surfaceBackupPtr, bufferSize);
info->lastFrameRemainder = -1;
}
Expand Down Expand Up @@ -86,7 +95,7 @@ Java_pl_droidsonroids_gif_GifInfoHandle_bindSurface(JNIEnv *env, jclass __unused
if (info->currentIndex > 0) {
memcpy(buffer.bits, oldBufferBits, bufferSize);
}
const uint_fast16_t frameDuration = getBitmap(buffer.bits, info);
const uint_fast32_t frameDuration = getBitmap(buffer.bits, info);

ANativeWindow_unlockAndPost(window);

Expand Down

0 comments on commit b61da4a

Please sign in to comment.