Skip to content

Commit

Permalink
Fix static decoding of interlaced or downsampled transparent GIFs.
Browse files Browse the repository at this point in the history
The GifDecoder was NPEing, forcing Glide to fall back to BitmapFactory,
which can only decode static images.

Fixes #2698
  • Loading branch information
sjudd committed Dec 8, 2017
1 parent d8f6224 commit b64f23d
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,120 @@ public class GifDrawableTest {

@Before
public void setUp() {
// Required for us to add a View to a Window.
assumeTrue(Build.VERSION.SDK_INT < Build.VERSION_CODES.M);

context = getTargetContext();
mainHandler = new Handler(Looper.getMainLooper());
}

@Test
public void loadGif_withInterlacedTransparentGif_sizeOriginal_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.interlaced_transparent_gif)
.submit()
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_withInterlacedTransparentGif_downsampled_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.interlaced_transparent_gif)
.submit(10, 10)
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_withTransparentGif_sizeOriginal_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.transparent_gif)
.submit()
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_withTransparentGif_downsampled_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.transparent_gif)
.submit(10, 10)
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_withOpaqueGif_sizeOriginal_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.opaque_gif)
.submit()
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_withOpaqueGif_downsampled_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.opaque_gif)
.submit(10, 10)
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_withOpaqueInterlacedGif_sizeOriginal_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.opaque_interlaced_gif)
.submit()
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_withOpaqueInterlacedGif_downsampled_succeeds()
throws ExecutionException, InterruptedException {
GifDrawable gifDrawable =
GlideApp.with(context)
.asGif()
.load(ResourceIds.raw.opaque_interlaced_gif)
.submit(10, 10)
.get();
assertThat(gifDrawable).isNotNull();
gifDrawable.stop();
}

@Test
public void loadGif_intoImageView_afterStop_restartsGif()
throws ExecutionException, InterruptedException {
// Required for us to add a View to a Window.
assumeTrue(Build.VERSION.SDK_INT < Build.VERSION_CODES.M);

// Mimic the state the Drawable can get into if it was loaded into a View previously and stopped
// so that it ended up with a pending frame that finished after the stop call.
final GifDrawable gifDrawable = GlideApp.with(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ private ResourceIds() {
public interface raw {
int dl_world_anim = getResourceId("raw", "dl_world_anim");
int canonical = getResourceId("raw", "canonical");
int interlaced_transparent_gif = getResourceId("raw", "interlaced_transparent_gif");
int transparent_gif = getResourceId("raw", "transparent_gif");
int opaque_gif = getResourceId("raw", "opaque_gif");
int opaque_interlaced_gif = getResourceId("raw", "opaque_interlaced_gif");
}

public interface drawable {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added instrumentation/src/main/res/raw/opaque_gif.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,7 @@ private void copyCopyIntoScratchRobust(GifFrame currentFrame) {
averageColor = act[currentColorIndex];
if (averageColor != COLOR_TRANSPARENT_BLACK) {
dest[dx] = averageColor;
} else if (
isFirstFrameTransparent == null && isFirstFrame && !isFirstFrameTransparent) {
} else if (isFirstFrame && isFirstFrameTransparent == null) {
isFirstFrameTransparent = true;
}
sx += sampleSize;
Expand All @@ -619,7 +618,7 @@ private void copyCopyIntoScratchRobust(GifFrame currentFrame) {
averageColor = averageColorsNear(sx, maxPositionInSource, currentFrame.iw);
if (averageColor != COLOR_TRANSPARENT_BLACK) {
dest[dx] = averageColor;
} else if (isFirstFrame && !isFirstFrameTransparent) {
} else if (isFirstFrame && isFirstFrameTransparent == null) {
isFirstFrameTransparent = true;
}
sx += sampleSize;
Expand All @@ -635,7 +634,6 @@ private void copyCopyIntoScratchRobust(GifFrame currentFrame) {
}
}


@ColorInt
private int averageColorsNear(int positionInMainPixels, int maxPositionInMainPixels,
int currentFrameIw) {
Expand Down

0 comments on commit b64f23d

Please sign in to comment.