Skip to content

Commit

Permalink
Bug 1291059 - Yield in the GIF decoder at the beginning of a new fram…
Browse files Browse the repository at this point in the history
…e, not at the end of the previous frame. r=edwin
  • Loading branch information
sethfowler committed Aug 2, 2016
1 parent 251edf1 commit a2a790e
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 23 deletions.
55 changes: 33 additions & 22 deletions image/decoders/nsGIFDecoder2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,6 @@ nsGIFDecoder2::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
return FinishedGlobalColorTable();
case State::BLOCK_HEADER:
return ReadBlockHeader(aData);
case State::BLOCK_HEADER_AFTER_YIELD:
return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
case State::EXTENSION_HEADER:
return ReadExtensionHeader(aData);
case State::GRAPHIC_CONTROL_EXTENSION:
Expand All @@ -484,6 +482,8 @@ nsGIFDecoder2::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
return ReadNetscapeExtensionData(aData);
case State::IMAGE_DESCRIPTOR:
return ReadImageDescriptor(aData);
case State::FINISH_IMAGE_DESCRIPTOR:
return FinishImageDescriptor(aData);
case State::LOCAL_COLOR_TABLE:
return ReadLocalColorTable(aData, aLength);
case State::FINISHED_LOCAL_COLOR_TABLE:
Expand Down Expand Up @@ -754,29 +754,40 @@ nsGIFDecoder2::ReadNetscapeExtensionData(const char* aData)
LexerTransition<nsGIFDecoder2::State>
nsGIFDecoder2::ReadImageDescriptor(const char* aData)
{
if (mGIFStruct.images_decoded == 1) {
if (!HasAnimation()) {
// We should've already called PostIsAnimated(); this must be a corrupt
// animated image with a first frame timeout of zero. Signal that we're
// animated now, before the first-frame decode early exit below, so that
// RasterImage can detect that this happened.
PostIsAnimated(FrameTimeout::FromRawMilliseconds(0));
}
// On the first frame, we don't need to yield, and none of the other checks
// below apply, so we can just jump right into FinishImageDescriptor().
if (mGIFStruct.images_decoded == 0) {
return FinishImageDescriptor(aData);
}

if (IsFirstFrameDecode()) {
// We're about to get a second frame, but we only want the first. Stop
// decoding now.
FinishInternal();
return Transition::TerminateSuccess();
}
if (!HasAnimation()) {
// We should've already called PostIsAnimated(); this must be a corrupt
// animated image with a first frame timeout of zero. Signal that we're
// animated now, before the first-frame decode early exit below, so that
// RasterImage can detect that this happened.
PostIsAnimated(FrameTimeout::FromRawMilliseconds(0));
}

if (mDownscaler) {
MOZ_ASSERT_UNREACHABLE("Doing downscale-during-decode for an animated "
"image?");
mDownscaler.reset();
}
if (IsFirstFrameDecode()) {
// We're about to get a second frame, but we only want the first. Stop
// decoding now.
FinishInternal();
return Transition::TerminateSuccess();
}

if (mDownscaler) {
MOZ_ASSERT_UNREACHABLE("Doing downscale-during-decode for an animated "
"image?");
mDownscaler.reset();
}

// Yield to allow access to the previous frame before we start a new one.
return Transition::ToAfterYield(State::FINISH_IMAGE_DESCRIPTOR);
}

LexerTransition<nsGIFDecoder2::State>
nsGIFDecoder2::FinishImageDescriptor(const char* aData)
{
IntRect frameRect;

// Get image offsets with respect to the screen origin.
Expand Down Expand Up @@ -972,7 +983,7 @@ nsGIFDecoder2::ReadImageDataSubBlock(const char* aData)
if (subBlockLength == 0) {
// We hit the block terminator.
EndImageFrame();
return Transition::ToAfterYield(State::BLOCK_HEADER_AFTER_YIELD);
return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
}

if (mGIFStruct.pixels_remaining == 0) {
Expand Down
3 changes: 2 additions & 1 deletion image/decoders/nsGIFDecoder2.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ class nsGIFDecoder2 : public Decoder
GLOBAL_COLOR_TABLE,
FINISHED_GLOBAL_COLOR_TABLE,
BLOCK_HEADER,
BLOCK_HEADER_AFTER_YIELD,
EXTENSION_HEADER,
GRAPHIC_CONTROL_EXTENSION,
APPLICATION_IDENTIFIER,
NETSCAPE_EXTENSION_SUB_BLOCK,
NETSCAPE_EXTENSION_DATA,
IMAGE_DESCRIPTOR,
FINISH_IMAGE_DESCRIPTOR,
LOCAL_COLOR_TABLE,
FINISHED_LOCAL_COLOR_TABLE,
IMAGE_DATA_BLOCK,
Expand All @@ -110,6 +110,7 @@ class nsGIFDecoder2 : public Decoder
LexerTransition<State> ReadNetscapeExtensionSubBlock(const char* aData);
LexerTransition<State> ReadNetscapeExtensionData(const char* aData);
LexerTransition<State> ReadImageDescriptor(const char* aData);
LexerTransition<State> FinishImageDescriptor(const char* aData);
LexerTransition<State> ReadLocalColorTable(const char* aData, size_t aLength);
LexerTransition<State> FinishedLocalColorTable();
LexerTransition<State> ReadImageDataBlock(const char* aData);
Expand Down

0 comments on commit a2a790e

Please sign in to comment.