Bug 1829125 - Align the PHC area to the jemalloc chunk size r=glandium
[gecko.git] / image / decoders / nsGIFDecoder2.cpp
blob9b2de9124ad809b8f128b1f9fd7affc58093a6d8
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 The Graphics Interchange Format(c) is the copyright property of CompuServe
8 Incorporated. Only CompuServe Incorporated is authorized to define, redefine,
9 enhance, alter, modify or change in any way the definition of the format.
11 CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free
12 license for the use of the Graphics Interchange Format(sm) in computer
13 software; computer software utilizing GIF(sm) must acknowledge ownership of the
14 Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in
15 User and Technical Documentation. Computer software utilizing GIF, which is
16 distributed or may be distributed without User or Technical Documentation must
17 display to the screen or printer a message acknowledging ownership of the
18 Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in
19 this case, the acknowledgement may be displayed in an opening screen or leading
20 banner, or a closing screen or trailing banner. A message such as the following
21 may be used:
23 "The Graphics Interchange Format(c) is the Copyright property of
24 CompuServe Incorporated. GIF(sm) is a Service Mark property of
25 CompuServe Incorporated."
27 For further information, please contact :
29 CompuServe Incorporated
30 Graphics Technology Department
31 5000 Arlington Center Boulevard
32 Columbus, Ohio 43220
33 U. S. A.
35 CompuServe Incorporated maintains a mailing list with all those individuals and
36 organizations who wish to receive copies of this document when it is corrected
37 or revised. This service is offered free of charge; please provide us with your
38 mailing address.
41 #include "nsGIFDecoder2.h"
43 #include <stddef.h>
45 #include "imgFrame.h"
46 #include "mozilla/EndianUtils.h"
47 #include "RasterImage.h"
48 #include "SurfacePipeFactory.h"
50 #include "gfxColor.h"
51 #include "gfxPlatform.h"
52 #include "qcms.h"
53 #include <algorithm>
54 #include "mozilla/Telemetry.h"
56 using namespace mozilla::gfx;
58 using std::max;
60 namespace mozilla {
61 namespace image {
63 //////////////////////////////////////////////////////////////////////
64 // GIF Decoder Implementation
66 static const size_t GIF_HEADER_LEN = 6;
67 static const size_t GIF_SCREEN_DESCRIPTOR_LEN = 7;
68 static const size_t BLOCK_HEADER_LEN = 1;
69 static const size_t SUB_BLOCK_HEADER_LEN = 1;
70 static const size_t EXTENSION_HEADER_LEN = 2;
71 static const size_t GRAPHIC_CONTROL_EXTENSION_LEN = 4;
72 static const size_t APPLICATION_EXTENSION_LEN = 11;
73 static const size_t IMAGE_DESCRIPTOR_LEN = 9;
75 // Masks for reading color table information from packed fields in the screen
76 // descriptor and image descriptor blocks.
77 static const uint8_t PACKED_FIELDS_COLOR_TABLE_BIT = 0x80;
78 static const uint8_t PACKED_FIELDS_INTERLACED_BIT = 0x40;
79 static const uint8_t PACKED_FIELDS_TABLE_DEPTH_MASK = 0x07;
81 nsGIFDecoder2::nsGIFDecoder2(RasterImage* aImage)
82 : Decoder(aImage),
83 mLexer(Transition::To(State::GIF_HEADER, GIF_HEADER_LEN),
84 Transition::TerminateSuccess()),
85 mOldColor(0),
86 mCurrentFrameIndex(-1),
87 mColorTablePos(0),
88 mColormap(nullptr),
89 mColormapSize(0),
90 mColorMask('\0'),
91 mGIFOpen(false),
92 mSawTransparency(false),
93 mSwizzleFn(nullptr) {
94 // Clear out the structure, excluding the arrays. Ensure that the global
95 // colormap is initialized as opaque.
96 memset(&mGIFStruct, 0, sizeof(mGIFStruct));
97 memset(mGIFStruct.global_colormap, 0xFF, sizeof(mGIFStruct.global_colormap));
99 // Each color table will need to be unpacked.
100 mSwizzleFn = SwizzleRow(SurfaceFormat::R8G8B8, SurfaceFormat::OS_RGBA);
101 MOZ_ASSERT(mSwizzleFn);
104 nsGIFDecoder2::~nsGIFDecoder2() { free(mGIFStruct.local_colormap); }
106 nsresult nsGIFDecoder2::FinishInternal() {
107 MOZ_ASSERT(!HasError(), "Shouldn't call FinishInternal after error!");
109 // If the GIF got cut off, handle it anyway
110 if (!IsMetadataDecode() && mGIFOpen) {
111 if (mCurrentFrameIndex == mGIFStruct.images_decoded) {
112 EndImageFrame();
114 PostDecodeDone(mGIFStruct.loop_count);
115 mGIFOpen = false;
118 return NS_OK;
121 void nsGIFDecoder2::FlushImageData() {
122 Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
123 if (!invalidRect) {
124 return;
127 PostInvalidation(invalidRect->mInputSpaceRect,
128 Some(invalidRect->mOutputSpaceRect));
131 //******************************************************************************
132 // GIF decoder callback methods. Part of public API for GIF2
133 //******************************************************************************
135 //******************************************************************************
136 void nsGIFDecoder2::BeginGIF() {
137 if (mGIFOpen) {
138 return;
141 mGIFOpen = true;
143 PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
146 bool nsGIFDecoder2::CheckForTransparency(const OrientedIntRect& aFrameRect) {
147 // Check if the image has a transparent color in its palette.
148 if (mGIFStruct.is_transparent) {
149 PostHasTransparency();
150 return true;
153 // This is a bit of a hack. Some sites will use a 1x1 gif that includes no
154 // header information indicating it is transparent, no palette, and no image
155 // data at all (so no pixels get written) to represent a transparent pixel
156 // using the absolute least number of bytes. Generally things are setup to
157 // detect transparency without decoding the image data. So to detect this kind
158 // of transparency without decoing the image data we would have to assume
159 // every gif is transparent, which we would like to avoid. Changing things so
160 // that we can detect transparency at any point of decoding is a bigger change
161 // and not worth it for one questionable 1x1 gif. Using this "trick" for
162 // anything but 1x1 transparent spacer gifs doesn't make sense, so it's
163 // reasonable to target 1x1 gifs just for this.
164 if (mGIFStruct.screen_width == 1 && mGIFStruct.screen_height == 1) {
165 PostHasTransparency();
166 return true;
169 if (mGIFStruct.images_decoded > 0) {
170 return false; // We only care about first frame padding below.
173 // If we need padding on the first frame, that means we don't draw into part
174 // of the image at all. Report that as transparency.
175 OrientedIntRect imageRect(0, 0, mGIFStruct.screen_width,
176 mGIFStruct.screen_height);
177 if (!imageRect.IsEqualEdges(aFrameRect)) {
178 PostHasTransparency();
179 mSawTransparency = true; // Make sure we don't optimize it away.
180 return true;
183 return false;
186 //******************************************************************************
187 nsresult nsGIFDecoder2::BeginImageFrame(const OrientedIntRect& aFrameRect,
188 uint16_t aDepth, bool aIsInterlaced) {
189 MOZ_ASSERT(HasSize());
191 bool hasTransparency = CheckForTransparency(aFrameRect);
193 // Make sure there's no animation if we're downscaling.
194 MOZ_ASSERT_IF(Size() != OutputSize(), !GetImageMetadata().HasAnimation());
196 Maybe<AnimationParams> animParams;
197 if (!IsFirstFrameDecode()) {
198 animParams.emplace(aFrameRect.ToUnknownRect(),
199 FrameTimeout::FromRawMilliseconds(mGIFStruct.delay_time),
200 uint32_t(mGIFStruct.images_decoded), BlendMethod::OVER,
201 DisposalMethod(mGIFStruct.disposal_method));
204 SurfacePipeFlags pipeFlags =
205 aIsInterlaced ? SurfacePipeFlags::DEINTERLACE : SurfacePipeFlags();
207 gfx::SurfaceFormat format;
208 if (mGIFStruct.images_decoded == 0) {
209 // The first frame may be displayed progressively.
210 pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY;
212 // Only allow opaque surfaces if we are decoding a single image without
213 // transparency. For an animation, there isn't much benefit to RGBX given
214 // the current frame is constantly changing, and there are many risks
215 // since BlendAnimationFilter is able to clear rows of data.
216 format = hasTransparency || animParams ? SurfaceFormat::OS_RGBA
217 : SurfaceFormat::OS_RGBX;
218 } else {
219 format = SurfaceFormat::OS_RGBA;
222 Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
223 this, Size(), OutputSize(), aFrameRect, format, format, animParams,
224 mTransform, pipeFlags);
225 mCurrentFrameIndex = mGIFStruct.images_decoded;
227 if (!pipe) {
228 mPipe = SurfacePipe();
229 return NS_ERROR_FAILURE;
232 mPipe = std::move(*pipe);
233 return NS_OK;
236 //******************************************************************************
237 void nsGIFDecoder2::EndImageFrame() {
238 Opacity opacity = Opacity::SOME_TRANSPARENCY;
240 if (mGIFStruct.images_decoded == 0) {
241 // We need to send invalidations for the first frame.
242 FlushImageData();
244 // The first frame was preallocated with alpha; if it wasn't transparent, we
245 // should fix that. We can also mark it opaque unconditionally if we didn't
246 // actually see any transparent pixels - this test is only valid for the
247 // first frame.
248 if (!mGIFStruct.is_transparent && !mSawTransparency) {
249 opacity = Opacity::FULLY_OPAQUE;
253 // Unconditionally increment images_decoded, because we unconditionally
254 // append frames in BeginImageFrame(). This ensures that images_decoded
255 // always refers to the frame in mImage we're currently decoding,
256 // even if some of them weren't decoded properly and thus are blank.
257 mGIFStruct.images_decoded++;
259 // Reset graphic control extension parameters that we shouldn't reuse
260 // between frames.
261 mGIFStruct.delay_time = 0;
263 // Tell the superclass we finished a frame
264 PostFrameStop(opacity);
266 // Reset the transparent pixel
267 if (mOldColor) {
268 mColormap[mGIFStruct.tpixel] = mOldColor;
269 mOldColor = 0;
272 mColormap = nullptr;
273 mColormapSize = 0;
274 mCurrentFrameIndex = -1;
277 template <typename PixelSize>
278 PixelSize nsGIFDecoder2::ColormapIndexToPixel(uint8_t aIndex) {
279 MOZ_ASSERT(sizeof(PixelSize) == sizeof(uint32_t));
281 // Retrieve the next color, clamping to the size of the colormap.
282 uint32_t color = mColormap[aIndex & mColorMask];
284 // Check for transparency.
285 if (mGIFStruct.is_transparent) {
286 mSawTransparency = mSawTransparency || color == 0;
289 return color;
292 template <>
293 uint8_t nsGIFDecoder2::ColormapIndexToPixel<uint8_t>(uint8_t aIndex) {
294 return aIndex & mColorMask;
297 template <typename PixelSize>
298 std::tuple<int32_t, Maybe<WriteState>> nsGIFDecoder2::YieldPixels(
299 const uint8_t* aData, size_t aLength, size_t* aBytesReadOut,
300 PixelSize* aPixelBlock, int32_t aBlockSize) {
301 MOZ_ASSERT(aData);
302 MOZ_ASSERT(aBytesReadOut);
303 MOZ_ASSERT(mGIFStruct.stackp >= mGIFStruct.stack);
305 // Advance to the next byte we should read.
306 const uint8_t* data = aData + *aBytesReadOut;
308 int32_t written = 0;
309 while (aBlockSize > written) {
310 // If we don't have any decoded data to yield, try to read some input and
311 // produce some.
312 if (mGIFStruct.stackp == mGIFStruct.stack) {
313 while (mGIFStruct.bits < mGIFStruct.codesize &&
314 *aBytesReadOut < aLength) {
315 // Feed the next byte into the decoder's 32-bit input buffer.
316 mGIFStruct.datum += int32_t(*data) << mGIFStruct.bits;
317 mGIFStruct.bits += 8;
318 data += 1;
319 *aBytesReadOut += 1;
322 if (mGIFStruct.bits < mGIFStruct.codesize) {
323 return std::make_tuple(written, Some(WriteState::NEED_MORE_DATA));
326 // Get the leading variable-length symbol from the data stream.
327 int code = mGIFStruct.datum & mGIFStruct.codemask;
328 mGIFStruct.datum >>= mGIFStruct.codesize;
329 mGIFStruct.bits -= mGIFStruct.codesize;
331 const int clearCode = ClearCode();
333 // Reset the dictionary to its original state, if requested
334 if (code == clearCode) {
335 mGIFStruct.codesize = mGIFStruct.datasize + 1;
336 mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
337 mGIFStruct.avail = clearCode + 2;
338 mGIFStruct.oldcode = -1;
339 return std::make_tuple(written, Some(WriteState::NEED_MORE_DATA));
342 // Check for explicit end-of-stream code. It should only appear after all
343 // image data, but if that was the case we wouldn't be in this function,
344 // so this is always an error condition.
345 if (code == (clearCode + 1)) {
346 return std::make_tuple(written, Some(WriteState::FAILURE));
349 if (mGIFStruct.oldcode == -1) {
350 if (code >= MAX_BITS) {
351 // The code's too big; something's wrong.
352 return std::make_tuple(written, Some(WriteState::FAILURE));
355 mGIFStruct.firstchar = mGIFStruct.oldcode = code;
357 // Yield a pixel at the appropriate index in the colormap.
358 mGIFStruct.pixels_remaining--;
359 aPixelBlock[written++] =
360 ColormapIndexToPixel<PixelSize>(mGIFStruct.suffix[code]);
361 continue;
364 int incode = code;
365 if (code >= mGIFStruct.avail) {
366 *mGIFStruct.stackp++ = mGIFStruct.firstchar;
367 code = mGIFStruct.oldcode;
369 if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
370 // Stack overflow; something's wrong.
371 return std::make_tuple(written, Some(WriteState::FAILURE));
375 while (code >= clearCode) {
376 if ((code >= MAX_BITS) || (code == mGIFStruct.prefix[code])) {
377 return std::make_tuple(written, Some(WriteState::FAILURE));
380 *mGIFStruct.stackp++ = mGIFStruct.suffix[code];
381 code = mGIFStruct.prefix[code];
383 if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
384 // Stack overflow; something's wrong.
385 return std::make_tuple(written, Some(WriteState::FAILURE));
389 *mGIFStruct.stackp++ = mGIFStruct.firstchar = mGIFStruct.suffix[code];
391 // Define a new codeword in the dictionary.
392 if (mGIFStruct.avail < 4096) {
393 mGIFStruct.prefix[mGIFStruct.avail] = mGIFStruct.oldcode;
394 mGIFStruct.suffix[mGIFStruct.avail] = mGIFStruct.firstchar;
395 mGIFStruct.avail++;
397 // If we've used up all the codewords of a given length increase the
398 // length of codewords by one bit, but don't exceed the specified
399 // maximum codeword size of 12 bits.
400 if (((mGIFStruct.avail & mGIFStruct.codemask) == 0) &&
401 (mGIFStruct.avail < 4096)) {
402 mGIFStruct.codesize++;
403 mGIFStruct.codemask += mGIFStruct.avail;
407 mGIFStruct.oldcode = incode;
410 if (MOZ_UNLIKELY(mGIFStruct.stackp <= mGIFStruct.stack)) {
411 MOZ_ASSERT_UNREACHABLE("No decoded data but we didn't return early?");
412 return std::make_tuple(written, Some(WriteState::FAILURE));
415 // Yield a pixel at the appropriate index in the colormap.
416 mGIFStruct.pixels_remaining--;
417 aPixelBlock[written++] =
418 ColormapIndexToPixel<PixelSize>(*--mGIFStruct.stackp);
421 return std::make_tuple(written, Maybe<WriteState>());
424 /// Expand the colormap from RGB to Packed ARGB as needed by Cairo.
425 /// And apply any LCMS transformation.
426 void nsGIFDecoder2::ConvertColormap(uint32_t* aColormap, uint32_t aColors) {
427 if (!aColors) {
428 return;
431 // Apply CMS transformation if enabled and available
432 if (mCMSMode == CMSMode::All) {
433 qcms_transform* transform = GetCMSsRGBTransform(SurfaceFormat::R8G8B8);
434 if (transform) {
435 qcms_transform_data(transform, aColormap, aColormap, aColors);
439 // Expand color table from RGB to BGRA.
440 MOZ_ASSERT(mSwizzleFn);
441 uint8_t* data = reinterpret_cast<uint8_t*>(aColormap);
442 mSwizzleFn(data, data, aColors);
445 LexerResult nsGIFDecoder2::DoDecode(SourceBufferIterator& aIterator,
446 IResumable* aOnResume) {
447 MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
449 return mLexer.Lex(
450 aIterator, aOnResume,
451 [=](State aState, const char* aData, size_t aLength) {
452 switch (aState) {
453 case State::GIF_HEADER:
454 return ReadGIFHeader(aData);
455 case State::SCREEN_DESCRIPTOR:
456 return ReadScreenDescriptor(aData);
457 case State::GLOBAL_COLOR_TABLE:
458 return ReadGlobalColorTable(aData, aLength);
459 case State::FINISHED_GLOBAL_COLOR_TABLE:
460 return FinishedGlobalColorTable();
461 case State::BLOCK_HEADER:
462 return ReadBlockHeader(aData);
463 case State::EXTENSION_HEADER:
464 return ReadExtensionHeader(aData);
465 case State::GRAPHIC_CONTROL_EXTENSION:
466 return ReadGraphicControlExtension(aData);
467 case State::APPLICATION_IDENTIFIER:
468 return ReadApplicationIdentifier(aData);
469 case State::NETSCAPE_EXTENSION_SUB_BLOCK:
470 return ReadNetscapeExtensionSubBlock(aData);
471 case State::NETSCAPE_EXTENSION_DATA:
472 return ReadNetscapeExtensionData(aData);
473 case State::IMAGE_DESCRIPTOR:
474 return ReadImageDescriptor(aData);
475 case State::FINISH_IMAGE_DESCRIPTOR:
476 return FinishImageDescriptor(aData);
477 case State::LOCAL_COLOR_TABLE:
478 return ReadLocalColorTable(aData, aLength);
479 case State::FINISHED_LOCAL_COLOR_TABLE:
480 return FinishedLocalColorTable();
481 case State::IMAGE_DATA_BLOCK:
482 return ReadImageDataBlock(aData);
483 case State::IMAGE_DATA_SUB_BLOCK:
484 return ReadImageDataSubBlock(aData);
485 case State::LZW_DATA:
486 return ReadLZWData(aData, aLength);
487 case State::SKIP_LZW_DATA:
488 return Transition::ContinueUnbuffered(State::SKIP_LZW_DATA);
489 case State::FINISHED_LZW_DATA:
490 return Transition::To(State::IMAGE_DATA_SUB_BLOCK,
491 SUB_BLOCK_HEADER_LEN);
492 case State::SKIP_SUB_BLOCKS:
493 return SkipSubBlocks(aData);
494 case State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS:
495 return Transition::ContinueUnbuffered(
496 State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS);
497 case State::FINISHED_SKIPPING_DATA:
498 return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
499 default:
500 MOZ_CRASH("Unknown State");
505 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadGIFHeader(
506 const char* aData) {
507 // We retrieve the version here but because many GIF encoders set header
508 // fields incorrectly, we barely use it; features which should only appear in
509 // GIF89a are always accepted.
510 if (strncmp(aData, "GIF87a", GIF_HEADER_LEN) == 0) {
511 mGIFStruct.version = 87;
512 } else if (strncmp(aData, "GIF89a", GIF_HEADER_LEN) == 0) {
513 mGIFStruct.version = 89;
514 } else {
515 return Transition::TerminateFailure();
518 return Transition::To(State::SCREEN_DESCRIPTOR, GIF_SCREEN_DESCRIPTOR_LEN);
521 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadScreenDescriptor(
522 const char* aData) {
523 mGIFStruct.screen_width = LittleEndian::readUint16(aData + 0);
524 mGIFStruct.screen_height = LittleEndian::readUint16(aData + 2);
526 const uint8_t packedFields = aData[4];
528 // XXX: Should we be capturing these values even if there is no global color
529 // table?
530 mGIFStruct.global_colormap_depth =
531 (packedFields & PACKED_FIELDS_TABLE_DEPTH_MASK) + 1;
532 mGIFStruct.global_colormap_count = 1 << mGIFStruct.global_colormap_depth;
534 // We ignore several fields in the header. We don't care about the 'sort
535 // flag', which indicates if the global color table's entries are sorted in
536 // order of importance - if we need to render this image for a device with a
537 // narrower color gamut than GIF supports we'll handle that at a different
538 // layer. We have no use for the pixel aspect ratio as well. Finally, we
539 // intentionally ignore the background color index, as implementing that
540 // feature would not be web compatible - when a GIF image frame doesn't cover
541 // the entire area of the image, the area that's not covered should always be
542 // transparent.
544 if (packedFields & PACKED_FIELDS_COLOR_TABLE_BIT) {
545 MOZ_ASSERT(mColorTablePos == 0);
547 // We read the global color table in unbuffered mode since it can be quite
548 // large and it'd be preferable to avoid unnecessary copies.
549 const size_t globalColorTableSize = 3 * mGIFStruct.global_colormap_count;
550 return Transition::ToUnbuffered(State::FINISHED_GLOBAL_COLOR_TABLE,
551 State::GLOBAL_COLOR_TABLE,
552 globalColorTableSize);
555 return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
558 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadGlobalColorTable(
559 const char* aData, size_t aLength) {
560 uint8_t* dest =
561 reinterpret_cast<uint8_t*>(mGIFStruct.global_colormap) + mColorTablePos;
562 memcpy(dest, aData, aLength);
563 mColorTablePos += aLength;
564 return Transition::ContinueUnbuffered(State::GLOBAL_COLOR_TABLE);
567 LexerTransition<nsGIFDecoder2::State>
568 nsGIFDecoder2::FinishedGlobalColorTable() {
569 ConvertColormap(mGIFStruct.global_colormap, mGIFStruct.global_colormap_count);
570 mColorTablePos = 0;
571 return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
574 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadBlockHeader(
575 const char* aData) {
576 // Determine what type of block we're dealing with.
577 switch (aData[0]) {
578 case GIF_EXTENSION_INTRODUCER:
579 return Transition::To(State::EXTENSION_HEADER, EXTENSION_HEADER_LEN);
581 case GIF_IMAGE_SEPARATOR:
582 return Transition::To(State::IMAGE_DESCRIPTOR, IMAGE_DESCRIPTOR_LEN);
584 case GIF_TRAILER:
585 FinishInternal();
586 return Transition::TerminateSuccess();
588 default:
589 // If we get anything other than GIF_IMAGE_SEPARATOR,
590 // GIF_EXTENSION_INTRODUCER, or GIF_TRAILER, there is extraneous data
591 // between blocks. The GIF87a spec tells us to keep reading until we find
592 // an image separator, but GIF89a says such a file is corrupt. We follow
593 // GIF89a and bail out.
595 if (mGIFStruct.images_decoded > 0) {
596 // The file is corrupt, but we successfully decoded some frames, so we
597 // may as well consider the decode successful and display them.
598 FinishInternal();
599 return Transition::TerminateSuccess();
602 // No images decoded; there is nothing to display.
603 return Transition::TerminateFailure();
607 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadExtensionHeader(
608 const char* aData) {
609 const uint8_t label = aData[0];
610 const uint8_t extensionHeaderLength = aData[1];
612 // If the extension header is zero length, just treat it as a block terminator
613 // and move on to the next block immediately.
614 if (extensionHeaderLength == 0) {
615 return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
618 switch (label) {
619 case GIF_GRAPHIC_CONTROL_LABEL:
620 // The GIF spec mandates that the Control Extension header block length is
621 // 4 bytes, and the parser for this block reads 4 bytes, so we must
622 // enforce that the buffer contains at least this many bytes. If the GIF
623 // specifies a different length, we allow that, so long as it's larger;
624 // the additional data will simply be ignored.
625 return Transition::To(
626 State::GRAPHIC_CONTROL_EXTENSION,
627 max<uint8_t>(extensionHeaderLength, GRAPHIC_CONTROL_EXTENSION_LEN));
629 case GIF_APPLICATION_EXTENSION_LABEL:
630 // Again, the spec specifies that an application extension header is 11
631 // bytes, but for compatibility with GIFs in the wild, we allow deviation
632 // from the spec. This is important for real-world compatibility, as GIFs
633 // in the wild exist with application extension headers that are both
634 // shorter and longer than 11 bytes. However, we only try to actually
635 // interpret the application extension if the length is correct;
636 // otherwise, we just skip the block unconditionally.
637 return extensionHeaderLength == APPLICATION_EXTENSION_LEN
638 ? Transition::To(State::APPLICATION_IDENTIFIER,
639 extensionHeaderLength)
640 : Transition::ToUnbuffered(
641 State::FINISHED_SKIPPING_DATA,
642 State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
643 extensionHeaderLength);
645 default:
646 // Skip over any other type of extension block, including comment and
647 // plain text blocks.
648 return Transition::ToUnbuffered(State::FINISHED_SKIPPING_DATA,
649 State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
650 extensionHeaderLength);
654 LexerTransition<nsGIFDecoder2::State>
655 nsGIFDecoder2::ReadGraphicControlExtension(const char* aData) {
656 mGIFStruct.is_transparent = aData[0] & 0x1;
657 mGIFStruct.tpixel = uint8_t(aData[3]);
658 mGIFStruct.disposal_method = (aData[0] >> 2) & 0x7;
660 if (mGIFStruct.disposal_method == 4) {
661 // Some encoders (and apparently some specs) represent
662 // DisposalMethod::RESTORE_PREVIOUS as 4, but 3 is used in the canonical
663 // spec and is more popular, so we normalize to 3.
664 mGIFStruct.disposal_method = 3;
665 } else if (mGIFStruct.disposal_method > 4) {
666 // This GIF is using a disposal method which is undefined in the spec.
667 // Treat it as DisposalMethod::NOT_SPECIFIED.
668 mGIFStruct.disposal_method = 0;
671 DisposalMethod method = DisposalMethod(mGIFStruct.disposal_method);
672 if (method == DisposalMethod::CLEAR_ALL || method == DisposalMethod::CLEAR) {
673 // We may have to display the background under this image during animation
674 // playback, so we regard it as transparent.
675 PostHasTransparency();
678 mGIFStruct.delay_time = LittleEndian::readUint16(aData + 1) * 10;
679 if (!HasAnimation() && mGIFStruct.delay_time > 0) {
680 PostIsAnimated(FrameTimeout::FromRawMilliseconds(mGIFStruct.delay_time));
683 return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
686 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadApplicationIdentifier(
687 const char* aData) {
688 if ((strncmp(aData, "NETSCAPE2.0", 11) == 0) ||
689 (strncmp(aData, "ANIMEXTS1.0", 11) == 0)) {
690 // This is a Netscape application extension block.
691 return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
692 SUB_BLOCK_HEADER_LEN);
695 // This is an application extension we don't care about. Just skip it.
696 return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
699 LexerTransition<nsGIFDecoder2::State>
700 nsGIFDecoder2::ReadNetscapeExtensionSubBlock(const char* aData) {
701 const uint8_t blockLength = aData[0];
702 if (blockLength == 0) {
703 // We hit the block terminator.
704 return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
707 // We consume a minimum of 3 bytes in accordance with the specs for the
708 // Netscape application extension block, such as they are.
709 const size_t extensionLength = max<uint8_t>(blockLength, 3);
710 return Transition::To(State::NETSCAPE_EXTENSION_DATA, extensionLength);
713 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadNetscapeExtensionData(
714 const char* aData) {
715 // Documentation for NETSCAPE2.0 / ANIMEXTS1.0 extensions can be found at:
716 // https://wiki.whatwg.org/wiki/GIF
717 static const uint8_t NETSCAPE_LOOPING_EXTENSION_SUB_BLOCK_ID = 1;
718 static const uint8_t NETSCAPE_BUFFERING_EXTENSION_SUB_BLOCK_ID = 2;
720 const uint8_t subBlockID = aData[0] & 7;
721 switch (subBlockID) {
722 case NETSCAPE_LOOPING_EXTENSION_SUB_BLOCK_ID:
723 // This is looping extension.
724 mGIFStruct.loop_count = LittleEndian::readUint16(aData + 1);
725 // Zero loop count is infinite animation loop request.
726 if (mGIFStruct.loop_count == 0) {
727 mGIFStruct.loop_count = -1;
730 return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
731 SUB_BLOCK_HEADER_LEN);
733 case NETSCAPE_BUFFERING_EXTENSION_SUB_BLOCK_ID:
734 // We allow, but ignore, this extension.
735 return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
736 SUB_BLOCK_HEADER_LEN);
738 default:
739 return Transition::TerminateFailure();
743 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadImageDescriptor(
744 const char* aData) {
745 // On the first frame, we don't need to yield, and none of the other checks
746 // below apply, so we can just jump right into FinishImageDescriptor().
747 if (mGIFStruct.images_decoded == 0) {
748 return FinishImageDescriptor(aData);
751 if (!HasAnimation()) {
752 // We should've already called PostIsAnimated(); this must be a corrupt
753 // animated image with a first frame timeout of zero. Signal that we're
754 // animated now, before the first-frame decode early exit below, so that
755 // RasterImage can detect that this happened.
756 PostIsAnimated(FrameTimeout::FromRawMilliseconds(0));
759 if (IsFirstFrameDecode()) {
760 // We're about to get a second frame, but we only want the first. Stop
761 // decoding now.
762 FinishInternal();
763 return Transition::TerminateSuccess();
766 MOZ_ASSERT(Size() == OutputSize(), "Downscaling an animated image?");
768 // Yield to allow access to the previous frame before we start a new one.
769 return Transition::ToAfterYield(State::FINISH_IMAGE_DESCRIPTOR);
772 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::FinishImageDescriptor(
773 const char* aData) {
774 OrientedIntRect frameRect;
776 // Get image offsets with respect to the screen origin.
777 frameRect.SetRect(
778 LittleEndian::readUint16(aData + 0), LittleEndian::readUint16(aData + 2),
779 LittleEndian::readUint16(aData + 4), LittleEndian::readUint16(aData + 6));
781 if (!mGIFStruct.images_decoded) {
782 // Work around GIF files where
783 // * at least one of the logical screen dimensions is smaller than the
784 // same dimension in the first image, or
785 // * GIF87a files where the first image's dimensions do not match the
786 // logical screen dimensions.
787 if (mGIFStruct.screen_height < frameRect.Height() ||
788 mGIFStruct.screen_width < frameRect.Width() ||
789 mGIFStruct.version == 87) {
790 mGIFStruct.screen_height = frameRect.Height();
791 mGIFStruct.screen_width = frameRect.Width();
792 frameRect.MoveTo(0, 0);
795 // Create the image container with the right size.
796 BeginGIF();
797 if (HasError()) {
798 // Setting the size led to an error.
799 return Transition::TerminateFailure();
802 // If we're doing a metadata decode, we're done.
803 if (IsMetadataDecode()) {
804 CheckForTransparency(frameRect);
805 FinishInternal();
806 return Transition::TerminateSuccess();
810 // Work around broken GIF files that have zero frame width or height; in this
811 // case, we'll treat the frame as having the same size as the overall image.
812 if (frameRect.Height() == 0 || frameRect.Width() == 0) {
813 frameRect.SetHeight(mGIFStruct.screen_height);
814 frameRect.SetWidth(mGIFStruct.screen_width);
816 // If that still resulted in zero frame width or height, give up.
817 if (frameRect.Height() == 0 || frameRect.Width() == 0) {
818 return Transition::TerminateFailure();
822 // Determine |depth| (log base 2 of the number of colors in the palette).
823 bool haveLocalColorTable = false;
824 uint16_t depth = 0;
825 uint8_t packedFields = aData[8];
827 if (packedFields & PACKED_FIELDS_COLOR_TABLE_BIT) {
828 // Get the palette depth from the local color table.
829 depth = (packedFields & PACKED_FIELDS_TABLE_DEPTH_MASK) + 1;
830 haveLocalColorTable = true;
831 } else {
832 // Get the palette depth from the global color table.
833 depth = mGIFStruct.global_colormap_depth;
836 // If the transparent color index is greater than the number of colors in the
837 // color table, we may need a higher color depth than |depth| would specify.
838 // Our internal representation of the image will instead use |realDepth|,
839 // which is the smallest color depth that can accommodate the existing palette
840 // *and* the transparent color index.
841 uint16_t realDepth = depth;
842 while (mGIFStruct.tpixel >= (1 << realDepth) && realDepth < 8) {
843 realDepth++;
846 // Create a mask used to ensure that color values fit within the colormap.
847 mColorMask = 0xFF >> (8 - realDepth);
849 // Determine if this frame is interlaced or not.
850 const bool isInterlaced = packedFields & PACKED_FIELDS_INTERLACED_BIT;
852 // Create the SurfacePipe we'll use to write output for this frame.
853 if (NS_FAILED(BeginImageFrame(frameRect, realDepth, isInterlaced))) {
854 return Transition::TerminateFailure();
857 // Clear state from last image.
858 mGIFStruct.pixels_remaining =
859 int64_t(frameRect.Width()) * int64_t(frameRect.Height());
861 if (haveLocalColorTable) {
862 // We have a local color table, so prepare to read it into the palette of
863 // the current frame.
864 mGIFStruct.local_colormap_size = 1 << depth;
866 if (!mColormap) {
867 // Ensure our current colormap buffer is large enough to hold the new one.
868 mColormapSize = sizeof(uint32_t) << realDepth;
869 if (mGIFStruct.local_colormap_buffer_size < mColormapSize) {
870 if (mGIFStruct.local_colormap) {
871 free(mGIFStruct.local_colormap);
873 mGIFStruct.local_colormap_buffer_size = mColormapSize;
874 mGIFStruct.local_colormap =
875 static_cast<uint32_t*>(moz_xmalloc(mColormapSize));
876 // Ensure the local colormap is initialized as opaque.
877 memset(mGIFStruct.local_colormap, 0xFF, mColormapSize);
878 } else {
879 mColormapSize = mGIFStruct.local_colormap_buffer_size;
882 mColormap = mGIFStruct.local_colormap;
885 MOZ_ASSERT(mColormap);
887 const size_t size = 3 << depth;
888 if (mColormapSize > size) {
889 // Clear the part of the colormap which will be unused with this palette.
890 // If a GIF references an invalid palette entry, ensure the entry is
891 // opaque white. This is needed for Skia as if it isn't, RGBX surfaces
892 // will cause blending issues with Skia.
893 memset(reinterpret_cast<uint8_t*>(mColormap) + size, 0xFF,
894 mColormapSize - size);
897 MOZ_ASSERT(mColorTablePos == 0);
899 // We read the local color table in unbuffered mode since it can be quite
900 // large and it'd be preferable to avoid unnecessary copies.
901 return Transition::ToUnbuffered(State::FINISHED_LOCAL_COLOR_TABLE,
902 State::LOCAL_COLOR_TABLE, size);
905 // There's no local color table; copy the global color table into the palette
906 // of the current frame.
907 if (mColormap) {
908 memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
909 } else {
910 mColormap = mGIFStruct.global_colormap;
913 return Transition::To(State::IMAGE_DATA_BLOCK, BLOCK_HEADER_LEN);
916 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadLocalColorTable(
917 const char* aData, size_t aLength) {
918 uint8_t* dest = reinterpret_cast<uint8_t*>(mColormap) + mColorTablePos;
919 memcpy(dest, aData, aLength);
920 mColorTablePos += aLength;
921 return Transition::ContinueUnbuffered(State::LOCAL_COLOR_TABLE);
924 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::FinishedLocalColorTable() {
925 ConvertColormap(mColormap, mGIFStruct.local_colormap_size);
926 mColorTablePos = 0;
927 return Transition::To(State::IMAGE_DATA_BLOCK, BLOCK_HEADER_LEN);
930 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadImageDataBlock(
931 const char* aData) {
932 // Make sure the transparent pixel is transparent in the colormap.
933 if (mGIFStruct.is_transparent) {
934 // Save the old value so we can restore it later.
935 if (mColormap == mGIFStruct.global_colormap) {
936 mOldColor = mColormap[mGIFStruct.tpixel];
938 mColormap[mGIFStruct.tpixel] = 0;
941 // Initialize the LZW decoder.
942 mGIFStruct.datasize = uint8_t(aData[0]);
943 if (mGIFStruct.datasize > MAX_LZW_BITS) {
944 return Transition::TerminateFailure();
946 const int clearCode = ClearCode();
947 if (clearCode >= MAX_BITS) {
948 return Transition::TerminateFailure();
951 mGIFStruct.avail = clearCode + 2;
952 mGIFStruct.oldcode = -1;
953 mGIFStruct.codesize = mGIFStruct.datasize + 1;
954 mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
955 mGIFStruct.datum = mGIFStruct.bits = 0;
957 // Initialize the tables.
958 for (int i = 0; i < clearCode; i++) {
959 mGIFStruct.suffix[i] = i;
962 mGIFStruct.stackp = mGIFStruct.stack;
964 // Begin reading image data sub-blocks.
965 return Transition::To(State::IMAGE_DATA_SUB_BLOCK, SUB_BLOCK_HEADER_LEN);
968 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadImageDataSubBlock(
969 const char* aData) {
970 const uint8_t subBlockLength = aData[0];
971 if (subBlockLength == 0) {
972 // We hit the block terminator.
973 EndImageFrame();
974 return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
977 if (mGIFStruct.pixels_remaining == 0) {
978 // We've already written to the entire image; we should've hit the block
979 // terminator at this point. This image is corrupt, but we'll tolerate it.
981 if (subBlockLength == GIF_TRAILER) {
982 // This GIF is missing the block terminator for the final block; we'll put
983 // up with it.
984 FinishInternal();
985 return Transition::TerminateSuccess();
988 // We're not at the end of the image, so just skip the extra data.
989 return Transition::ToUnbuffered(State::FINISHED_LZW_DATA,
990 State::SKIP_LZW_DATA, subBlockLength);
993 // Handle the standard case: there's data in the sub-block and pixels left to
994 // fill in the image. We read the sub-block unbuffered so we can get pixels on
995 // the screen as soon as possible.
996 return Transition::ToUnbuffered(State::FINISHED_LZW_DATA, State::LZW_DATA,
997 subBlockLength);
1000 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::ReadLZWData(
1001 const char* aData, size_t aLength) {
1002 const uint8_t* data = reinterpret_cast<const uint8_t*>(aData);
1003 size_t length = aLength;
1005 while (mGIFStruct.pixels_remaining > 0 &&
1006 (length > 0 || mGIFStruct.bits >= mGIFStruct.codesize)) {
1007 size_t bytesRead = 0;
1009 auto result = mPipe.WritePixelBlocks<uint32_t>(
1010 [&](uint32_t* aPixelBlock, int32_t aBlockSize) {
1011 return YieldPixels<uint32_t>(data, length, &bytesRead, aPixelBlock,
1012 aBlockSize);
1015 if (MOZ_UNLIKELY(bytesRead > length)) {
1016 MOZ_ASSERT_UNREACHABLE("Overread?");
1017 bytesRead = length;
1020 // Advance our position in the input based upon what YieldPixel() consumed.
1021 data += bytesRead;
1022 length -= bytesRead;
1024 switch (result) {
1025 case WriteState::NEED_MORE_DATA:
1026 continue;
1028 case WriteState::FINISHED:
1029 NS_WARNING_ASSERTION(mGIFStruct.pixels_remaining <= 0,
1030 "too many pixels");
1031 mGIFStruct.pixels_remaining = 0;
1032 break;
1034 case WriteState::FAILURE:
1035 return Transition::TerminateFailure();
1039 // We're done, but keep going until we consume all the data in the sub-block.
1040 return Transition::ContinueUnbuffered(State::LZW_DATA);
1043 LexerTransition<nsGIFDecoder2::State> nsGIFDecoder2::SkipSubBlocks(
1044 const char* aData) {
1045 // In the SKIP_SUB_BLOCKS state we skip over data sub-blocks that we're not
1046 // interested in. Blocks consist of a block header (which can be up to 255
1047 // bytes in length) and a series of data sub-blocks. Each data sub-block
1048 // consists of a single byte length value, followed by the data itself. A data
1049 // sub-block with a length of zero terminates the overall block.
1050 // SKIP_SUB_BLOCKS reads a sub-block length value. If it's zero, we've arrived
1051 // at the next block. Otherwise, we enter the SKIP_DATA_THEN_SKIP_SUB_BLOCKS
1052 // state to skip over the sub-block data and return to SKIP_SUB_BLOCKS at the
1053 // start of the next sub-block.
1055 const uint8_t nextSubBlockLength = aData[0];
1056 if (nextSubBlockLength == 0) {
1057 // We hit the block terminator, so the sequence of data sub-blocks is over;
1058 // begin processing another block.
1059 return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
1062 // Skip to the next sub-block length value.
1063 return Transition::ToUnbuffered(State::FINISHED_SKIPPING_DATA,
1064 State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
1065 nextSubBlockLength);
1068 Maybe<Telemetry::HistogramID> nsGIFDecoder2::SpeedHistogram() const {
1069 return Some(Telemetry::IMAGE_DECODE_SPEED_GIF);
1072 } // namespace image
1073 } // namespace mozilla