Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/image/decoders/nsGIFDecoder2.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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.
10
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:
22
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."
26
27
For further information, please contact :
28
29
    CompuServe Incorporated
30
    Graphics Technology Department
31
    5000 Arlington Center Boulevard
32
    Columbus, Ohio  43220
33
    U. S. A.
34
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.
39
*/
40
41
#include "nsGIFDecoder2.h"
42
43
#include <stddef.h>
44
45
#include "imgFrame.h"
46
#include "mozilla/EndianUtils.h"
47
#include "nsIInputStream.h"
48
#include "RasterImage.h"
49
#include "SurfacePipeFactory.h"
50
51
#include "gfxColor.h"
52
#include "gfxPlatform.h"
53
#include "qcms.h"
54
#include <algorithm>
55
#include "mozilla/Telemetry.h"
56
57
using namespace mozilla::gfx;
58
59
using std::max;
60
61
namespace mozilla {
62
namespace image {
63
64
//////////////////////////////////////////////////////////////////////
65
// GIF Decoder Implementation
66
67
static const size_t GIF_HEADER_LEN = 6;
68
static const size_t GIF_SCREEN_DESCRIPTOR_LEN = 7;
69
static const size_t BLOCK_HEADER_LEN = 1;
70
static const size_t SUB_BLOCK_HEADER_LEN = 1;
71
static const size_t EXTENSION_HEADER_LEN = 2;
72
static const size_t GRAPHIC_CONTROL_EXTENSION_LEN = 4;
73
static const size_t APPLICATION_EXTENSION_LEN = 11;
74
static const size_t IMAGE_DESCRIPTOR_LEN = 9;
75
76
// Masks for reading color table information from packed fields in the screen
77
// descriptor and image descriptor blocks.
78
static const uint8_t PACKED_FIELDS_COLOR_TABLE_BIT = 0x80;
79
static const uint8_t PACKED_FIELDS_INTERLACED_BIT = 0x40;
80
static const uint8_t PACKED_FIELDS_TABLE_DEPTH_MASK = 0x07;
81
82
nsGIFDecoder2::nsGIFDecoder2(RasterImage* aImage)
83
  : Decoder(aImage)
84
  , mLexer(Transition::To(State::GIF_HEADER, GIF_HEADER_LEN),
85
           Transition::TerminateSuccess())
86
  , mOldColor(0)
87
  , mCurrentFrameIndex(-1)
88
  , mColorTablePos(0)
89
  , mColorMask('\0')
90
  , mGIFOpen(false)
91
  , mSawTransparency(false)
92
0
{
93
0
  // Clear out the structure, excluding the arrays.
94
0
  memset(&mGIFStruct, 0, sizeof(mGIFStruct));
95
0
}
96
97
nsGIFDecoder2::~nsGIFDecoder2()
98
0
{
99
0
  free(mGIFStruct.local_colormap);
100
0
}
101
102
nsresult
103
nsGIFDecoder2::FinishInternal()
104
0
{
105
0
  MOZ_ASSERT(!HasError(), "Shouldn't call FinishInternal after error!");
106
0
107
0
  // If the GIF got cut off, handle it anyway
108
0
  if (!IsMetadataDecode() && mGIFOpen) {
109
0
    if (mCurrentFrameIndex == mGIFStruct.images_decoded) {
110
0
      EndImageFrame();
111
0
    }
112
0
    PostDecodeDone(mGIFStruct.loop_count);
113
0
    mGIFOpen = false;
114
0
  }
115
0
116
0
  return NS_OK;
117
0
}
118
119
void
120
nsGIFDecoder2::FlushImageData()
121
0
{
122
0
  Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
123
0
  if (!invalidRect) {
124
0
    return;
125
0
  }
126
0
127
0
  PostInvalidation(invalidRect->mInputSpaceRect,
128
0
                   Some(invalidRect->mOutputSpaceRect));
129
0
}
130
131
//******************************************************************************
132
// GIF decoder callback methods. Part of public API for GIF2
133
//******************************************************************************
134
135
//******************************************************************************
136
void
137
nsGIFDecoder2::BeginGIF()
138
0
{
139
0
  if (mGIFOpen) {
140
0
    return;
141
0
  }
142
0
143
0
  mGIFOpen = true;
144
0
145
0
  PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
146
0
}
147
148
bool
149
nsGIFDecoder2::CheckForTransparency(const IntRect& aFrameRect)
150
0
{
151
0
  // Check if the image has a transparent color in its palette.
152
0
  if (mGIFStruct.is_transparent) {
153
0
    PostHasTransparency();
154
0
    return true;
155
0
  }
156
0
157
0
  if (mGIFStruct.images_decoded > 0) {
158
0
    return false;  // We only care about first frame padding below.
159
0
  }
160
0
161
0
  // If we need padding on the first frame, that means we don't draw into part
162
0
  // of the image at all. Report that as transparency.
163
0
  IntRect imageRect(0, 0, mGIFStruct.screen_width, mGIFStruct.screen_height);
164
0
  if (!imageRect.IsEqualEdges(aFrameRect)) {
165
0
    PostHasTransparency();
166
0
    mSawTransparency = true;  // Make sure we don't optimize it away.
167
0
    return true;
168
0
  }
169
0
170
0
  return false;
171
0
}
172
173
//******************************************************************************
174
nsresult
175
nsGIFDecoder2::BeginImageFrame(const IntRect& aFrameRect,
176
                               uint16_t aDepth,
177
                               bool aIsInterlaced)
178
0
{
179
0
  MOZ_ASSERT(HasSize());
180
0
181
0
  bool hasTransparency = CheckForTransparency(aFrameRect);
182
0
  bool blendAnimation = ShouldBlendAnimation();
183
0
184
0
  // Make sure there's no animation if we're downscaling.
185
0
  MOZ_ASSERT_IF(Size() != OutputSize(), !GetImageMetadata().HasAnimation());
186
0
187
0
  AnimationParams animParams {
188
0
    aFrameRect,
189
0
    FrameTimeout::FromRawMilliseconds(mGIFStruct.delay_time),
190
0
    uint32_t(mGIFStruct.images_decoded),
191
0
    BlendMethod::OVER,
192
0
    DisposalMethod(mGIFStruct.disposal_method)
193
0
  };
194
0
195
0
  SurfacePipeFlags pipeFlags = aIsInterlaced
196
0
                             ? SurfacePipeFlags::DEINTERLACE
197
0
                             : SurfacePipeFlags();
198
0
199
0
  gfx::SurfaceFormat format;
200
0
  if (mGIFStruct.images_decoded == 0) {
201
0
    // The first frame may be displayed progressively.
202
0
    pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY;
203
0
204
0
    format = hasTransparency ? SurfaceFormat::B8G8R8A8
205
0
                             : SurfaceFormat::B8G8R8X8;
206
0
  } else {
207
0
    format = SurfaceFormat::B8G8R8A8;
208
0
  }
209
0
210
0
  if (blendAnimation) {
211
0
    pipeFlags |= SurfacePipeFlags::BLEND_ANIMATION;
212
0
  }
213
0
214
0
  Maybe<SurfacePipe> pipe;
215
0
  if (mGIFStruct.images_decoded == 0 || blendAnimation) {
216
0
    // The first frame is always decoded into an RGB surface.
217
0
    pipe =
218
0
      SurfacePipeFactory::CreateSurfacePipe(this, Size(), OutputSize(),
219
0
                                            aFrameRect, format,
220
0
                                            Some(animParams), pipeFlags);
221
0
  } else {
222
0
    // This is an animation frame (and not the first). To minimize the memory
223
0
    // usage of animations, the image data is stored in paletted form.
224
0
    //
225
0
    // We should never use paletted surfaces with a draw target directly, so
226
0
    // the only practical difference between B8G8R8A8 and B8G8R8X8 is the
227
0
    // cleared pixel value if we get truncated. We want 0 in that case to
228
0
    // ensure it is an acceptable value for the color map as was the case
229
0
    // historically.
230
0
    MOZ_ASSERT(Size() == OutputSize());
231
0
    pipe =
232
0
      SurfacePipeFactory::CreatePalettedSurfacePipe(this, Size(), aFrameRect,
233
0
                                                    format, aDepth,
234
0
                                                    Some(animParams),
235
0
                                                    pipeFlags);
236
0
  }
237
0
238
0
  mCurrentFrameIndex = mGIFStruct.images_decoded;
239
0
240
0
  if (!pipe) {
241
0
    mPipe = SurfacePipe();
242
0
    return NS_ERROR_FAILURE;
243
0
  }
244
0
245
0
  mPipe = std::move(*pipe);
246
0
  return NS_OK;
247
0
}
248
249
250
//******************************************************************************
251
void
252
nsGIFDecoder2::EndImageFrame()
253
0
{
254
0
  Opacity opacity = Opacity::SOME_TRANSPARENCY;
255
0
256
0
  if (mGIFStruct.images_decoded == 0) {
257
0
    // We need to send invalidations for the first frame.
258
0
    FlushImageData();
259
0
260
0
    // The first frame was preallocated with alpha; if it wasn't transparent, we
261
0
    // should fix that. We can also mark it opaque unconditionally if we didn't
262
0
    // actually see any transparent pixels - this test is only valid for the
263
0
    // first frame.
264
0
    if (!mGIFStruct.is_transparent && !mSawTransparency) {
265
0
      opacity = Opacity::FULLY_OPAQUE;
266
0
    }
267
0
  }
268
0
269
0
  // Unconditionally increment images_decoded, because we unconditionally
270
0
  // append frames in BeginImageFrame(). This ensures that images_decoded
271
0
  // always refers to the frame in mImage we're currently decoding,
272
0
  // even if some of them weren't decoded properly and thus are blank.
273
0
  mGIFStruct.images_decoded++;
274
0
275
0
  // Tell the superclass we finished a frame
276
0
  PostFrameStop(opacity);
277
0
278
0
  // Reset the transparent pixel
279
0
  if (mOldColor) {
280
0
    mColormap[mGIFStruct.tpixel] = mOldColor;
281
0
    mOldColor = 0;
282
0
  }
283
0
284
0
  mCurrentFrameIndex = -1;
285
0
}
286
287
template <typename PixelSize>
288
PixelSize
289
nsGIFDecoder2::ColormapIndexToPixel(uint8_t aIndex)
290
0
{
291
0
  MOZ_ASSERT(sizeof(PixelSize) == sizeof(uint32_t));
292
0
293
0
  // Retrieve the next color, clamping to the size of the colormap.
294
0
  uint32_t color = mColormap[aIndex & mColorMask];
295
0
296
0
  // Check for transparency.
297
0
  if (mGIFStruct.is_transparent) {
298
0
    mSawTransparency = mSawTransparency || color == 0;
299
0
  }
300
0
301
0
  return color;
302
0
}
303
304
template <>
305
uint8_t
306
nsGIFDecoder2::ColormapIndexToPixel<uint8_t>(uint8_t aIndex)
307
0
{
308
0
  return aIndex & mColorMask;
309
0
}
310
311
template <typename PixelSize>
312
Tuple<int32_t, Maybe<WriteState>>
313
nsGIFDecoder2::YieldPixels(const uint8_t* aData,
314
                           size_t aLength,
315
                           size_t* aBytesReadOut,
316
                           PixelSize* aPixelBlock,
317
                           int32_t aBlockSize)
318
0
{
319
0
  MOZ_ASSERT(aData);
320
0
  MOZ_ASSERT(aBytesReadOut);
321
0
  MOZ_ASSERT(mGIFStruct.stackp >= mGIFStruct.stack);
322
0
323
0
  // Advance to the next byte we should read.
324
0
  const uint8_t* data = aData + *aBytesReadOut;
325
0
326
0
  int32_t written = 0;
327
0
  while (aBlockSize > written) {
328
0
    // If we don't have any decoded data to yield, try to read some input and
329
0
    // produce some.
330
0
    if (mGIFStruct.stackp == mGIFStruct.stack) {
331
0
      while (mGIFStruct.bits < mGIFStruct.codesize && *aBytesReadOut < aLength) {
332
0
        // Feed the next byte into the decoder's 32-bit input buffer.
333
0
        mGIFStruct.datum += int32_t(*data) << mGIFStruct.bits;
334
0
        mGIFStruct.bits += 8;
335
0
        data += 1;
336
0
        *aBytesReadOut += 1;
337
0
      }
338
0
339
0
      if (mGIFStruct.bits < mGIFStruct.codesize) {
340
0
        return MakeTuple(written, Some(WriteState::NEED_MORE_DATA));
341
0
      }
342
0
343
0
      // Get the leading variable-length symbol from the data stream.
344
0
      int code = mGIFStruct.datum & mGIFStruct.codemask;
345
0
      mGIFStruct.datum >>= mGIFStruct.codesize;
346
0
      mGIFStruct.bits -= mGIFStruct.codesize;
347
0
348
0
      const int clearCode = ClearCode();
349
0
350
0
      // Reset the dictionary to its original state, if requested
351
0
      if (code == clearCode) {
352
0
        mGIFStruct.codesize = mGIFStruct.datasize + 1;
353
0
        mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
354
0
        mGIFStruct.avail = clearCode + 2;
355
0
        mGIFStruct.oldcode = -1;
356
0
        return MakeTuple(written, Some(WriteState::NEED_MORE_DATA));
357
0
      }
358
0
359
0
      // Check for explicit end-of-stream code. It should only appear after all
360
0
      // image data, but if that was the case we wouldn't be in this function, so
361
0
      // this is always an error condition.
362
0
      if (code == (clearCode + 1)) {
363
0
        return MakeTuple(written, Some(WriteState::FAILURE));
364
0
      }
365
0
366
0
      if (mGIFStruct.oldcode == -1) {
367
0
        if (code >= MAX_BITS) {
368
0
          // The code's too big; something's wrong.
369
0
          return MakeTuple(written, Some(WriteState::FAILURE));
370
0
        }
371
0
372
0
        mGIFStruct.firstchar = mGIFStruct.oldcode = code;
373
0
374
0
        // Yield a pixel at the appropriate index in the colormap.
375
0
        mGIFStruct.pixels_remaining--;
376
0
        aPixelBlock[written++] =
377
0
          ColormapIndexToPixel<PixelSize>(mGIFStruct.suffix[code]);
378
0
        continue;
379
0
      }
380
0
381
0
      int incode = code;
382
0
      if (code >= mGIFStruct.avail) {
383
0
        *mGIFStruct.stackp++ = mGIFStruct.firstchar;
384
0
        code = mGIFStruct.oldcode;
385
0
386
0
        if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
387
0
          // Stack overflow; something's wrong.
388
0
          return MakeTuple(written, Some(WriteState::FAILURE));
389
0
        }
390
0
      }
391
0
392
0
      while (code >= clearCode) {
393
0
        if ((code >= MAX_BITS) || (code == mGIFStruct.prefix[code])) {
394
0
          return MakeTuple(written, Some(WriteState::FAILURE));
395
0
        }
396
0
397
0
        *mGIFStruct.stackp++ = mGIFStruct.suffix[code];
398
0
        code = mGIFStruct.prefix[code];
399
0
400
0
        if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
401
0
          // Stack overflow; something's wrong.
402
0
          return MakeTuple(written, Some(WriteState::FAILURE));
403
0
        }
404
0
      }
405
0
406
0
      *mGIFStruct.stackp++ = mGIFStruct.firstchar = mGIFStruct.suffix[code];
407
0
408
0
      // Define a new codeword in the dictionary.
409
0
      if (mGIFStruct.avail < 4096) {
410
0
        mGIFStruct.prefix[mGIFStruct.avail] = mGIFStruct.oldcode;
411
0
        mGIFStruct.suffix[mGIFStruct.avail] = mGIFStruct.firstchar;
412
0
        mGIFStruct.avail++;
413
0
414
0
        // If we've used up all the codewords of a given length increase the
415
0
        // length of codewords by one bit, but don't exceed the specified maximum
416
0
        // codeword size of 12 bits.
417
0
        if (((mGIFStruct.avail & mGIFStruct.codemask) == 0) &&
418
0
            (mGIFStruct.avail < 4096)) {
419
0
          mGIFStruct.codesize++;
420
0
          mGIFStruct.codemask += mGIFStruct.avail;
421
0
        }
422
0
      }
423
0
424
0
      mGIFStruct.oldcode = incode;
425
0
    }
426
0
427
0
    if (MOZ_UNLIKELY(mGIFStruct.stackp <= mGIFStruct.stack)) {
428
0
      MOZ_ASSERT_UNREACHABLE("No decoded data but we didn't return early?");
429
0
      return MakeTuple(written, Some(WriteState::FAILURE));
430
0
    }
431
0
432
0
    // Yield a pixel at the appropriate index in the colormap.
433
0
    mGIFStruct.pixels_remaining--;
434
0
    aPixelBlock[written++]
435
0
      = ColormapIndexToPixel<PixelSize>(*--mGIFStruct.stackp);
436
0
  }
437
0
438
0
  return MakeTuple(written, Maybe<WriteState>());
439
0
}
Unexecuted instantiation: mozilla::Tuple<int, mozilla::Maybe<mozilla::image::WriteState> > mozilla::image::nsGIFDecoder2::YieldPixels<unsigned int>(unsigned char const*, unsigned long, unsigned long*, unsigned int*, int)
Unexecuted instantiation: mozilla::Tuple<int, mozilla::Maybe<mozilla::image::WriteState> > mozilla::image::nsGIFDecoder2::YieldPixels<unsigned char>(unsigned char const*, unsigned long, unsigned long*, unsigned char*, int)
440
441
/// Expand the colormap from RGB to Packed ARGB as needed by Cairo.
442
/// And apply any LCMS transformation.
443
static void
444
ConvertColormap(uint32_t* aColormap, uint32_t aColors)
445
0
{
446
0
  // Apply CMS transformation if enabled and available
447
0
  if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
448
0
    qcms_transform* transform = gfxPlatform::GetCMSRGBTransform();
449
0
    if (transform) {
450
0
      qcms_transform_data(transform, aColormap, aColormap, aColors);
451
0
    }
452
0
  }
453
0
454
0
  // Convert from the GIF's RGB format to the Cairo format.
455
0
  // Work from end to begin, because of the in-place expansion
456
0
  uint8_t* from = ((uint8_t*)aColormap) + 3 * aColors;
457
0
  uint32_t* to = aColormap + aColors;
458
0
459
0
  // Convert color entries to Cairo format
460
0
461
0
  // set up for loops below
462
0
  if (!aColors) {
463
0
    return;
464
0
  }
465
0
  uint32_t c = aColors;
466
0
467
0
  // copy as bytes until source pointer is 32-bit-aligned
468
0
  // NB: can't use 32-bit reads, they might read off the end of the buffer
469
0
  for (; (NS_PTR_TO_UINT32(from) & 0x3) && c; --c) {
470
0
    from -= 3;
471
0
    *--to = gfxPackedPixel(0xFF, from[0], from[1], from[2]);
472
0
  }
473
0
474
0
  // bulk copy of pixels.
475
0
  while (c >= 4) {
476
0
    from -= 12;
477
0
    to   -=  4;
478
0
    c    -=  4;
479
0
    GFX_BLOCK_RGB_TO_FRGB(from,to);
480
0
  }
481
0
482
0
  // copy remaining pixel(s)
483
0
  // NB: can't use 32-bit reads, they might read off the end of the buffer
484
0
  while (c--) {
485
0
    from -= 3;
486
0
    *--to = gfxPackedPixel(0xFF, from[0], from[1], from[2]);
487
0
  }
488
0
}
489
490
LexerResult
491
nsGIFDecoder2::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
492
0
{
493
0
  MOZ_ASSERT(!HasError(), "Shouldn't call DoDecode after error!");
494
0
495
0
  return mLexer.Lex(aIterator, aOnResume,
496
0
                    [=](State aState, const char* aData, size_t aLength) {
497
0
    switch(aState) {
498
0
      case State::GIF_HEADER:
499
0
        return ReadGIFHeader(aData);
500
0
      case State::SCREEN_DESCRIPTOR:
501
0
        return ReadScreenDescriptor(aData);
502
0
      case State::GLOBAL_COLOR_TABLE:
503
0
        return ReadGlobalColorTable(aData, aLength);
504
0
      case State::FINISHED_GLOBAL_COLOR_TABLE:
505
0
        return FinishedGlobalColorTable();
506
0
      case State::BLOCK_HEADER:
507
0
        return ReadBlockHeader(aData);
508
0
      case State::EXTENSION_HEADER:
509
0
        return ReadExtensionHeader(aData);
510
0
      case State::GRAPHIC_CONTROL_EXTENSION:
511
0
        return ReadGraphicControlExtension(aData);
512
0
      case State::APPLICATION_IDENTIFIER:
513
0
        return ReadApplicationIdentifier(aData);
514
0
      case State::NETSCAPE_EXTENSION_SUB_BLOCK:
515
0
        return ReadNetscapeExtensionSubBlock(aData);
516
0
      case State::NETSCAPE_EXTENSION_DATA:
517
0
        return ReadNetscapeExtensionData(aData);
518
0
      case State::IMAGE_DESCRIPTOR:
519
0
        return ReadImageDescriptor(aData);
520
0
      case State::FINISH_IMAGE_DESCRIPTOR:
521
0
        return FinishImageDescriptor(aData);
522
0
      case State::LOCAL_COLOR_TABLE:
523
0
        return ReadLocalColorTable(aData, aLength);
524
0
      case State::FINISHED_LOCAL_COLOR_TABLE:
525
0
        return FinishedLocalColorTable();
526
0
      case State::IMAGE_DATA_BLOCK:
527
0
        return ReadImageDataBlock(aData);
528
0
      case State::IMAGE_DATA_SUB_BLOCK:
529
0
        return ReadImageDataSubBlock(aData);
530
0
      case State::LZW_DATA:
531
0
        return ReadLZWData(aData, aLength);
532
0
      case State::SKIP_LZW_DATA:
533
0
        return Transition::ContinueUnbuffered(State::SKIP_LZW_DATA);
534
0
      case State::FINISHED_LZW_DATA:
535
0
        return Transition::To(State::IMAGE_DATA_SUB_BLOCK, SUB_BLOCK_HEADER_LEN);
536
0
      case State::SKIP_SUB_BLOCKS:
537
0
        return SkipSubBlocks(aData);
538
0
      case State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS:
539
0
        return Transition::ContinueUnbuffered(State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS);
540
0
      case State::FINISHED_SKIPPING_DATA:
541
0
        return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
542
0
      default:
543
0
        MOZ_CRASH("Unknown State");
544
0
    }
545
0
  });
546
0
}
547
548
LexerTransition<nsGIFDecoder2::State>
549
nsGIFDecoder2::ReadGIFHeader(const char* aData)
550
0
{
551
0
  // We retrieve the version here but because many GIF encoders set header
552
0
  // fields incorrectly, we barely use it; features which should only appear in
553
0
  // GIF89a are always accepted.
554
0
  if (strncmp(aData, "GIF87a", GIF_HEADER_LEN) == 0) {
555
0
    mGIFStruct.version = 87;
556
0
  } else if (strncmp(aData, "GIF89a", GIF_HEADER_LEN) == 0) {
557
0
    mGIFStruct.version = 89;
558
0
  } else {
559
0
    return Transition::TerminateFailure();
560
0
  }
561
0
562
0
  return Transition::To(State::SCREEN_DESCRIPTOR, GIF_SCREEN_DESCRIPTOR_LEN);
563
0
}
564
565
LexerTransition<nsGIFDecoder2::State>
566
nsGIFDecoder2::ReadScreenDescriptor(const char* aData)
567
0
{
568
0
  mGIFStruct.screen_width  = LittleEndian::readUint16(aData + 0);
569
0
  mGIFStruct.screen_height = LittleEndian::readUint16(aData + 2);
570
0
571
0
  const uint8_t packedFields = aData[4];
572
0
573
0
  // XXX: Should we be capturing these values even if there is no global color
574
0
  // table?
575
0
  mGIFStruct.global_colormap_depth =
576
0
    (packedFields & PACKED_FIELDS_TABLE_DEPTH_MASK) + 1;
577
0
  mGIFStruct.global_colormap_count = 1 << mGIFStruct.global_colormap_depth;
578
0
579
0
  // We ignore several fields in the header. We don't care about the 'sort
580
0
  // flag', which indicates if the global color table's entries are sorted in
581
0
  // order of importance - if we need to render this image for a device with a
582
0
  // narrower color gamut than GIF supports we'll handle that at a different
583
0
  // layer. We have no use for the pixel aspect ratio as well. Finally, we
584
0
  // intentionally ignore the background color index, as implementing that
585
0
  // feature would not be web compatible - when a GIF image frame doesn't cover
586
0
  // the entire area of the image, the area that's not covered should always be
587
0
  // transparent.
588
0
589
0
  if (packedFields & PACKED_FIELDS_COLOR_TABLE_BIT) {
590
0
    MOZ_ASSERT(mColorTablePos == 0);
591
0
592
0
    // We read the global color table in unbuffered mode since it can be quite
593
0
    // large and it'd be preferable to avoid unnecessary copies.
594
0
    const size_t globalColorTableSize = 3 * mGIFStruct.global_colormap_count;
595
0
    return Transition::ToUnbuffered(State::FINISHED_GLOBAL_COLOR_TABLE,
596
0
                                    State::GLOBAL_COLOR_TABLE,
597
0
                                    globalColorTableSize);
598
0
  }
599
0
600
0
  return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
601
0
}
602
603
LexerTransition<nsGIFDecoder2::State>
604
nsGIFDecoder2::ReadGlobalColorTable(const char* aData, size_t aLength)
605
0
{
606
0
  uint8_t* dest = reinterpret_cast<uint8_t*>(mGIFStruct.global_colormap)
607
0
                + mColorTablePos;
608
0
  memcpy(dest, aData, aLength);
609
0
  mColorTablePos += aLength;
610
0
  return Transition::ContinueUnbuffered(State::GLOBAL_COLOR_TABLE);
611
0
}
612
613
LexerTransition<nsGIFDecoder2::State>
614
nsGIFDecoder2::FinishedGlobalColorTable()
615
0
{
616
0
  ConvertColormap(mGIFStruct.global_colormap, mGIFStruct.global_colormap_count);
617
0
  mColorTablePos = 0;
618
0
  return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
619
0
}
620
621
LexerTransition<nsGIFDecoder2::State>
622
nsGIFDecoder2::ReadBlockHeader(const char* aData)
623
0
{
624
0
  // Determine what type of block we're dealing with.
625
0
  switch (aData[0]) {
626
0
    case GIF_EXTENSION_INTRODUCER:
627
0
      return Transition::To(State::EXTENSION_HEADER, EXTENSION_HEADER_LEN);
628
0
629
0
    case GIF_IMAGE_SEPARATOR:
630
0
      return Transition::To(State::IMAGE_DESCRIPTOR, IMAGE_DESCRIPTOR_LEN);
631
0
632
0
    case GIF_TRAILER:
633
0
      FinishInternal();
634
0
      return Transition::TerminateSuccess();
635
0
636
0
    default:
637
0
      // If we get anything other than GIF_IMAGE_SEPARATOR,
638
0
      // GIF_EXTENSION_INTRODUCER, or GIF_TRAILER, there is extraneous data
639
0
      // between blocks. The GIF87a spec tells us to keep reading until we find
640
0
      // an image separator, but GIF89a says such a file is corrupt. We follow
641
0
      // GIF89a and bail out.
642
0
643
0
      if (mGIFStruct.images_decoded > 0) {
644
0
        // The file is corrupt, but we successfully decoded some frames, so we
645
0
        // may as well consider the decode successful and display them.
646
0
        FinishInternal();
647
0
        return Transition::TerminateSuccess();
648
0
      }
649
0
650
0
      // No images decoded; there is nothing to display.
651
0
      return Transition::TerminateFailure();
652
0
  }
653
0
}
654
655
LexerTransition<nsGIFDecoder2::State>
656
nsGIFDecoder2::ReadExtensionHeader(const char* aData)
657
0
{
658
0
  const uint8_t label = aData[0];
659
0
  const uint8_t extensionHeaderLength = aData[1];
660
0
661
0
  // If the extension header is zero length, just treat it as a block terminator
662
0
  // and move on to the next block immediately.
663
0
  if (extensionHeaderLength == 0) {
664
0
    return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
665
0
  }
666
0
667
0
  switch (label) {
668
0
    case GIF_GRAPHIC_CONTROL_LABEL:
669
0
      // The GIF spec mandates that the Control Extension header block length is
670
0
      // 4 bytes, and the parser for this block reads 4 bytes, so we must
671
0
      // enforce that the buffer contains at least this many bytes. If the GIF
672
0
      // specifies a different length, we allow that, so long as it's larger;
673
0
      // the additional data will simply be ignored.
674
0
      return Transition::To(State::GRAPHIC_CONTROL_EXTENSION,
675
0
                            max<uint8_t>(extensionHeaderLength,
676
0
                                         GRAPHIC_CONTROL_EXTENSION_LEN));
677
0
678
0
    case GIF_APPLICATION_EXTENSION_LABEL:
679
0
      // Again, the spec specifies that an application extension header is 11
680
0
      // bytes, but for compatibility with GIFs in the wild, we allow deviation
681
0
      // from the spec. This is important for real-world compatibility, as GIFs
682
0
      // in the wild exist with application extension headers that are both
683
0
      // shorter and longer than 11 bytes. However, we only try to actually
684
0
      // interpret the application extension if the length is correct;
685
0
      // otherwise, we just skip the block unconditionally.
686
0
      return extensionHeaderLength == APPLICATION_EXTENSION_LEN
687
0
           ? Transition::To(State::APPLICATION_IDENTIFIER, extensionHeaderLength)
688
0
           : Transition::ToUnbuffered(State::FINISHED_SKIPPING_DATA,
689
0
                                      State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
690
0
                                      extensionHeaderLength);
691
0
692
0
    default:
693
0
      // Skip over any other type of extension block, including comment and
694
0
      // plain text blocks.
695
0
      return Transition::ToUnbuffered(State::FINISHED_SKIPPING_DATA,
696
0
                                      State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
697
0
                                      extensionHeaderLength);
698
0
  }
699
0
}
700
701
LexerTransition<nsGIFDecoder2::State>
702
nsGIFDecoder2::ReadGraphicControlExtension(const char* aData)
703
0
{
704
0
  mGIFStruct.is_transparent = aData[0] & 0x1;
705
0
  mGIFStruct.tpixel = uint8_t(aData[3]);
706
0
  mGIFStruct.disposal_method = (aData[0] >> 2) & 0x7;
707
0
708
0
  if (mGIFStruct.disposal_method == 4) {
709
0
    // Some encoders (and apparently some specs) represent
710
0
    // DisposalMethod::RESTORE_PREVIOUS as 4, but 3 is used in the canonical
711
0
    // spec and is more popular, so we normalize to 3.
712
0
    mGIFStruct.disposal_method = 3;
713
0
  } else if (mGIFStruct.disposal_method > 4) {
714
0
    // This GIF is using a disposal method which is undefined in the spec.
715
0
    // Treat it as DisposalMethod::NOT_SPECIFIED.
716
0
    mGIFStruct.disposal_method = 0;
717
0
  }
718
0
719
0
  DisposalMethod method = DisposalMethod(mGIFStruct.disposal_method);
720
0
  if (method == DisposalMethod::CLEAR_ALL || method == DisposalMethod::CLEAR) {
721
0
    // We may have to display the background under this image during animation
722
0
    // playback, so we regard it as transparent.
723
0
    PostHasTransparency();
724
0
  }
725
0
726
0
  mGIFStruct.delay_time = LittleEndian::readUint16(aData + 1) * 10;
727
0
  if (mGIFStruct.delay_time > 0) {
728
0
    PostIsAnimated(FrameTimeout::FromRawMilliseconds(mGIFStruct.delay_time));
729
0
  }
730
0
731
0
  return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
732
0
}
733
734
LexerTransition<nsGIFDecoder2::State>
735
nsGIFDecoder2::ReadApplicationIdentifier(const char* aData)
736
0
{
737
0
  if ((strncmp(aData, "NETSCAPE2.0", 11) == 0) ||
738
0
      (strncmp(aData, "ANIMEXTS1.0", 11) == 0)) {
739
0
    // This is a Netscape application extension block.
740
0
    return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
741
0
                          SUB_BLOCK_HEADER_LEN);
742
0
  }
743
0
744
0
  // This is an application extension we don't care about. Just skip it.
745
0
  return Transition::To(State::SKIP_SUB_BLOCKS, SUB_BLOCK_HEADER_LEN);
746
0
}
747
748
LexerTransition<nsGIFDecoder2::State>
749
nsGIFDecoder2::ReadNetscapeExtensionSubBlock(const char* aData)
750
0
{
751
0
  const uint8_t blockLength = aData[0];
752
0
  if (blockLength == 0) {
753
0
    // We hit the block terminator.
754
0
    return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
755
0
  }
756
0
757
0
  // We consume a minimum of 3 bytes in accordance with the specs for the
758
0
  // Netscape application extension block, such as they are.
759
0
  const size_t extensionLength = max<uint8_t>(blockLength, 3);
760
0
  return Transition::To(State::NETSCAPE_EXTENSION_DATA, extensionLength);
761
0
}
762
763
LexerTransition<nsGIFDecoder2::State>
764
nsGIFDecoder2::ReadNetscapeExtensionData(const char* aData)
765
0
{
766
0
  // Documentation for NETSCAPE2.0 / ANIMEXTS1.0 extensions can be found at:
767
0
  //   https://wiki.whatwg.org/wiki/GIF
768
0
  static const uint8_t NETSCAPE_LOOPING_EXTENSION_SUB_BLOCK_ID = 1;
769
0
  static const uint8_t NETSCAPE_BUFFERING_EXTENSION_SUB_BLOCK_ID = 2;
770
0
771
0
  const uint8_t subBlockID = aData[0] & 7;
772
0
  switch (subBlockID) {
773
0
    case NETSCAPE_LOOPING_EXTENSION_SUB_BLOCK_ID:
774
0
      // This is looping extension.
775
0
      mGIFStruct.loop_count = LittleEndian::readUint16(aData + 1);
776
0
      // Zero loop count is infinite animation loop request.
777
0
      if (mGIFStruct.loop_count == 0) {
778
0
        mGIFStruct.loop_count = -1;
779
0
      }
780
0
781
0
      return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
782
0
                            SUB_BLOCK_HEADER_LEN);
783
0
784
0
    case NETSCAPE_BUFFERING_EXTENSION_SUB_BLOCK_ID:
785
0
      // We allow, but ignore, this extension.
786
0
      return Transition::To(State::NETSCAPE_EXTENSION_SUB_BLOCK,
787
0
                            SUB_BLOCK_HEADER_LEN);
788
0
789
0
    default:
790
0
      return Transition::TerminateFailure();
791
0
  }
792
0
}
793
794
LexerTransition<nsGIFDecoder2::State>
795
nsGIFDecoder2::ReadImageDescriptor(const char* aData)
796
0
{
797
0
  // On the first frame, we don't need to yield, and none of the other checks
798
0
  // below apply, so we can just jump right into FinishImageDescriptor().
799
0
  if (mGIFStruct.images_decoded == 0) {
800
0
    return FinishImageDescriptor(aData);
801
0
  }
802
0
803
0
  if (!HasAnimation()) {
804
0
    // We should've already called PostIsAnimated(); this must be a corrupt
805
0
    // animated image with a first frame timeout of zero. Signal that we're
806
0
    // animated now, before the first-frame decode early exit below, so that
807
0
    // RasterImage can detect that this happened.
808
0
    PostIsAnimated(FrameTimeout::FromRawMilliseconds(0));
809
0
  }
810
0
811
0
  if (IsFirstFrameDecode()) {
812
0
    // We're about to get a second frame, but we only want the first. Stop
813
0
    // decoding now.
814
0
    FinishInternal();
815
0
    return Transition::TerminateSuccess();
816
0
  }
817
0
818
0
  MOZ_ASSERT(Size() == OutputSize(), "Downscaling an animated image?");
819
0
820
0
  // Yield to allow access to the previous frame before we start a new one.
821
0
  return Transition::ToAfterYield(State::FINISH_IMAGE_DESCRIPTOR);
822
0
}
823
824
LexerTransition<nsGIFDecoder2::State>
825
nsGIFDecoder2::FinishImageDescriptor(const char* aData)
826
0
{
827
0
  IntRect frameRect;
828
0
829
0
  // Get image offsets with respect to the screen origin.
830
0
  frameRect.SetRect(LittleEndian::readUint16(aData + 0),
831
0
                    LittleEndian::readUint16(aData + 2),
832
0
                    LittleEndian::readUint16(aData + 4),
833
0
                    LittleEndian::readUint16(aData + 6));
834
0
835
0
  if (!mGIFStruct.images_decoded) {
836
0
    // Work around GIF files where
837
0
    //   * at least one of the logical screen dimensions is smaller than the
838
0
    //     same dimension in the first image, or
839
0
    //   * GIF87a files where the first image's dimensions do not match the
840
0
    //     logical screen dimensions.
841
0
    if (mGIFStruct.screen_height < frameRect.Height() ||
842
0
        mGIFStruct.screen_width < frameRect.Width() ||
843
0
        mGIFStruct.version == 87) {
844
0
      mGIFStruct.screen_height = frameRect.Height();
845
0
      mGIFStruct.screen_width = frameRect.Width();
846
0
      frameRect.MoveTo(0, 0);
847
0
    }
848
0
849
0
    // Create the image container with the right size.
850
0
    BeginGIF();
851
0
    if (HasError()) {
852
0
      // Setting the size led to an error.
853
0
      return Transition::TerminateFailure();
854
0
    }
855
0
856
0
    // If we're doing a metadata decode, we're done.
857
0
    if (IsMetadataDecode()) {
858
0
      CheckForTransparency(frameRect);
859
0
      FinishInternal();
860
0
      return Transition::TerminateSuccess();
861
0
    }
862
0
  }
863
0
864
0
  // Work around broken GIF files that have zero frame width or height; in this
865
0
  // case, we'll treat the frame as having the same size as the overall image.
866
0
  if (frameRect.Height() == 0 || frameRect.Width() == 0) {
867
0
    frameRect.SetHeight(mGIFStruct.screen_height);
868
0
    frameRect.SetWidth(mGIFStruct.screen_width);
869
0
870
0
    // If that still resulted in zero frame width or height, give up.
871
0
    if (frameRect.Height() == 0 || frameRect.Width() == 0) {
872
0
      return Transition::TerminateFailure();
873
0
    }
874
0
  }
875
0
876
0
  // Determine |depth| (log base 2 of the number of colors in the palette).
877
0
  bool haveLocalColorTable = false;
878
0
  uint16_t depth = 0;
879
0
  uint8_t packedFields = aData[8];
880
0
881
0
  if (packedFields & PACKED_FIELDS_COLOR_TABLE_BIT) {
882
0
    // Get the palette depth from the local color table.
883
0
    depth = (packedFields & PACKED_FIELDS_TABLE_DEPTH_MASK) + 1;
884
0
    haveLocalColorTable = true;
885
0
  } else {
886
0
    // Get the palette depth from the global color table.
887
0
    depth = mGIFStruct.global_colormap_depth;
888
0
  }
889
0
890
0
  // If the transparent color index is greater than the number of colors in the
891
0
  // color table, we may need a higher color depth than |depth| would specify.
892
0
  // Our internal representation of the image will instead use |realDepth|,
893
0
  // which is the smallest color depth that can accomodate the existing palette
894
0
  // *and* the transparent color index.
895
0
  uint16_t realDepth = depth;
896
0
  while (mGIFStruct.tpixel >= (1 << realDepth) &&
897
0
         realDepth < 8) {
898
0
    realDepth++;
899
0
  }
900
0
901
0
  // Create a mask used to ensure that color values fit within the colormap.
902
0
  mColorMask = 0xFF >> (8 - realDepth);
903
0
904
0
  // Determine if this frame is interlaced or not.
905
0
  const bool isInterlaced = packedFields & PACKED_FIELDS_INTERLACED_BIT;
906
0
907
0
  // Create the SurfacePipe we'll use to write output for this frame.
908
0
  if (NS_FAILED(BeginImageFrame(frameRect, realDepth, isInterlaced))) {
909
0
    return Transition::TerminateFailure();
910
0
  }
911
0
912
0
  // Clear state from last image.
913
0
  mGIFStruct.pixels_remaining =
914
0
    int64_t(frameRect.Width()) * int64_t(frameRect.Height());
915
0
916
0
  if (haveLocalColorTable) {
917
0
    // We have a local color table, so prepare to read it into the palette of
918
0
    // the current frame.
919
0
    mGIFStruct.local_colormap_size = 1 << depth;
920
0
921
0
    if (!mColormap) {
922
0
      // Allocate a buffer to store the local color tables. This could be if the
923
0
      // first frame has a local color table, or for subsequent frames when
924
0
      // blending the animation during decoding.
925
0
      MOZ_ASSERT(mGIFStruct.images_decoded == 0 || ShouldBlendAnimation());
926
0
927
0
      // Ensure our current colormap buffer is large enough to hold the new one.
928
0
      mColormapSize = sizeof(uint32_t) << realDepth;
929
0
      if (mGIFStruct.local_colormap_buffer_size < mColormapSize) {
930
0
        if (mGIFStruct.local_colormap) {
931
0
          free(mGIFStruct.local_colormap);
932
0
        }
933
0
        mGIFStruct.local_colormap_buffer_size = mColormapSize;
934
0
        mGIFStruct.local_colormap =
935
0
          static_cast<uint32_t*>(moz_xmalloc(mColormapSize));
936
0
      } else {
937
0
        mColormapSize = mGIFStruct.local_colormap_buffer_size;
938
0
      }
939
0
940
0
      mColormap = mGIFStruct.local_colormap;
941
0
    }
942
0
943
0
    MOZ_ASSERT(mColormap);
944
0
945
0
    const size_t size = 3 << depth;
946
0
    if (mColormapSize > size) {
947
0
      // Clear the part of the colormap which will be unused with this palette.
948
0
      // If a GIF references an invalid palette entry, ensure the entry is opaque white.
949
0
      // This is needed for Skia as if it isn't, RGBX surfaces will cause blending issues
950
0
      // with Skia.
951
0
      memset(reinterpret_cast<uint8_t*>(mColormap) + size, 0xFF,
952
0
             mColormapSize - size);
953
0
    }
954
0
955
0
    MOZ_ASSERT(mColorTablePos == 0);
956
0
957
0
    // We read the local color table in unbuffered mode since it can be quite
958
0
    // large and it'd be preferable to avoid unnecessary copies.
959
0
    return Transition::ToUnbuffered(State::FINISHED_LOCAL_COLOR_TABLE,
960
0
                                    State::LOCAL_COLOR_TABLE,
961
0
                                    size);
962
0
  }
963
0
964
0
  // There's no local color table; copy the global color table into the palette
965
0
  // of the current frame.
966
0
  if (mColormap) {
967
0
    memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
968
0
  } else {
969
0
    mColormap = mGIFStruct.global_colormap;
970
0
  }
971
0
972
0
  return Transition::To(State::IMAGE_DATA_BLOCK, BLOCK_HEADER_LEN);
973
0
}
974
975
LexerTransition<nsGIFDecoder2::State>
976
nsGIFDecoder2::ReadLocalColorTable(const char* aData, size_t aLength)
977
0
{
978
0
  uint8_t* dest = reinterpret_cast<uint8_t*>(mColormap) + mColorTablePos;
979
0
  memcpy(dest, aData, aLength);
980
0
  mColorTablePos += aLength;
981
0
  return Transition::ContinueUnbuffered(State::LOCAL_COLOR_TABLE);
982
0
}
983
984
LexerTransition<nsGIFDecoder2::State>
985
nsGIFDecoder2::FinishedLocalColorTable()
986
0
{
987
0
  ConvertColormap(mColormap, mGIFStruct.local_colormap_size);
988
0
  mColorTablePos = 0;
989
0
  return Transition::To(State::IMAGE_DATA_BLOCK, BLOCK_HEADER_LEN);
990
0
}
991
992
LexerTransition<nsGIFDecoder2::State>
993
nsGIFDecoder2::ReadImageDataBlock(const char* aData)
994
0
{
995
0
  // Make sure the transparent pixel is transparent in the colormap.
996
0
  if (mGIFStruct.is_transparent) {
997
0
    // Save the old value so we can restore it later.
998
0
    if (mColormap == mGIFStruct.global_colormap) {
999
0
        mOldColor = mColormap[mGIFStruct.tpixel];
1000
0
    }
1001
0
    mColormap[mGIFStruct.tpixel] = 0;
1002
0
  }
1003
0
1004
0
  // Initialize the LZW decoder.
1005
0
  mGIFStruct.datasize = uint8_t(aData[0]);
1006
0
  if (mGIFStruct.datasize > MAX_LZW_BITS) {
1007
0
    return Transition::TerminateFailure();
1008
0
  }
1009
0
  const int clearCode = ClearCode();
1010
0
  if (clearCode >= MAX_BITS) {
1011
0
    return Transition::TerminateFailure();
1012
0
  }
1013
0
1014
0
  mGIFStruct.avail = clearCode + 2;
1015
0
  mGIFStruct.oldcode = -1;
1016
0
  mGIFStruct.codesize = mGIFStruct.datasize + 1;
1017
0
  mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
1018
0
  mGIFStruct.datum = mGIFStruct.bits = 0;
1019
0
1020
0
  // Initialize the tables.
1021
0
  for (int i = 0; i < clearCode; i++) {
1022
0
    mGIFStruct.suffix[i] = i;
1023
0
  }
1024
0
1025
0
  mGIFStruct.stackp = mGIFStruct.stack;
1026
0
1027
0
  // Begin reading image data sub-blocks.
1028
0
  return Transition::To(State::IMAGE_DATA_SUB_BLOCK, SUB_BLOCK_HEADER_LEN);
1029
0
}
1030
1031
LexerTransition<nsGIFDecoder2::State>
1032
nsGIFDecoder2::ReadImageDataSubBlock(const char* aData)
1033
0
{
1034
0
  const uint8_t subBlockLength = aData[0];
1035
0
  if (subBlockLength == 0) {
1036
0
    // We hit the block terminator.
1037
0
    EndImageFrame();
1038
0
    return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
1039
0
  }
1040
0
1041
0
  if (mGIFStruct.pixels_remaining == 0) {
1042
0
    // We've already written to the entire image; we should've hit the block
1043
0
    // terminator at this point. This image is corrupt, but we'll tolerate it.
1044
0
1045
0
    if (subBlockLength == GIF_TRAILER) {
1046
0
      // This GIF is missing the block terminator for the final block; we'll put
1047
0
      // up with it.
1048
0
      FinishInternal();
1049
0
      return Transition::TerminateSuccess();
1050
0
    }
1051
0
1052
0
    // We're not at the end of the image, so just skip the extra data.
1053
0
    return Transition::ToUnbuffered(State::FINISHED_LZW_DATA,
1054
0
                                    State::SKIP_LZW_DATA,
1055
0
                                    subBlockLength);
1056
0
  }
1057
0
1058
0
  // Handle the standard case: there's data in the sub-block and pixels left to
1059
0
  // fill in the image. We read the sub-block unbuffered so we can get pixels on
1060
0
  // the screen as soon as possible.
1061
0
  return Transition::ToUnbuffered(State::FINISHED_LZW_DATA,
1062
0
                                  State::LZW_DATA,
1063
0
                                  subBlockLength);
1064
0
}
1065
1066
LexerTransition<nsGIFDecoder2::State>
1067
nsGIFDecoder2::ReadLZWData(const char* aData, size_t aLength)
1068
0
{
1069
0
  const uint8_t* data = reinterpret_cast<const uint8_t*>(aData);
1070
0
  size_t length = aLength;
1071
0
1072
0
  while (mGIFStruct.pixels_remaining > 0 &&
1073
0
         (length > 0 || mGIFStruct.bits >= mGIFStruct.codesize)) {
1074
0
    size_t bytesRead = 0;
1075
0
1076
0
    auto result = mGIFStruct.images_decoded == 0 || ShouldBlendAnimation()
1077
0
      ? mPipe.WritePixelBlocks<uint32_t>([&](uint32_t* aPixelBlock, int32_t aBlockSize) {
1078
0
          return YieldPixels<uint32_t>(data, length, &bytesRead, aPixelBlock, aBlockSize);
1079
0
        })
1080
0
      : mPipe.WritePixelBlocks<uint8_t>([&](uint8_t* aPixelBlock, int32_t aBlockSize) {
1081
0
          return YieldPixels<uint8_t>(data, length, &bytesRead, aPixelBlock, aBlockSize);
1082
0
        });
1083
0
1084
0
    if (MOZ_UNLIKELY(bytesRead > length)) {
1085
0
      MOZ_ASSERT_UNREACHABLE("Overread?");
1086
0
      bytesRead = length;
1087
0
    }
1088
0
1089
0
    // Advance our position in the input based upon what YieldPixel() consumed.
1090
0
    data += bytesRead;
1091
0
    length -= bytesRead;
1092
0
1093
0
    switch (result) {
1094
0
      case WriteState::NEED_MORE_DATA:
1095
0
        continue;
1096
0
1097
0
      case WriteState::FINISHED:
1098
0
        NS_WARNING_ASSERTION(mGIFStruct.pixels_remaining <= 0,
1099
0
                             "too many pixels");
1100
0
        mGIFStruct.pixels_remaining = 0;
1101
0
        break;
1102
0
1103
0
      case WriteState::FAILURE:
1104
0
        return Transition::TerminateFailure();
1105
0
    }
1106
0
  }
1107
0
1108
0
  // We're done, but keep going until we consume all the data in the sub-block.
1109
0
  return Transition::ContinueUnbuffered(State::LZW_DATA);
1110
0
}
1111
1112
LexerTransition<nsGIFDecoder2::State>
1113
nsGIFDecoder2::SkipSubBlocks(const char* aData)
1114
0
{
1115
0
  // In the SKIP_SUB_BLOCKS state we skip over data sub-blocks that we're not
1116
0
  // interested in. Blocks consist of a block header (which can be up to 255
1117
0
  // bytes in length) and a series of data sub-blocks. Each data sub-block
1118
0
  // consists of a single byte length value, followed by the data itself. A data
1119
0
  // sub-block with a length of zero terminates the overall block.
1120
0
  // SKIP_SUB_BLOCKS reads a sub-block length value. If it's zero, we've arrived
1121
0
  // at the next block. Otherwise, we enter the SKIP_DATA_THEN_SKIP_SUB_BLOCKS
1122
0
  // state to skip over the sub-block data and return to SKIP_SUB_BLOCKS at the
1123
0
  // start of the next sub-block.
1124
0
1125
0
  const uint8_t nextSubBlockLength = aData[0];
1126
0
  if (nextSubBlockLength == 0) {
1127
0
    // We hit the block terminator, so the sequence of data sub-blocks is over;
1128
0
    // begin processing another block.
1129
0
    return Transition::To(State::BLOCK_HEADER, BLOCK_HEADER_LEN);
1130
0
  }
1131
0
1132
0
  // Skip to the next sub-block length value.
1133
0
  return Transition::ToUnbuffered(State::FINISHED_SKIPPING_DATA,
1134
0
                                  State::SKIP_DATA_THEN_SKIP_SUB_BLOCKS,
1135
0
                                  nextSubBlockLength);
1136
0
}
1137
1138
Maybe<Telemetry::HistogramID>
1139
nsGIFDecoder2::SpeedHistogram() const
1140
0
{
1141
0
  return Some(Telemetry::IMAGE_DECODE_SPEED_GIF);
1142
0
}
1143
1144
} // namespace image
1145
} // namespace mozilla