Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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.
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.
39 */
41 #include <stddef.h>
43 #include "nsGIFDecoder2.h"
44 #include "nsIInputStream.h"
45 #include "RasterImage.h"
47 #include "gfxColor.h"
48 #include "gfxPlatform.h"
49 #include "qcms.h"
50 #include <algorithm>
52 namespace mozilla {
53 namespace image {
55 /*
56 * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
57 *
58 * Colormaps are directly copied in the resp. global_colormap or the local_colormap of the PAL image frame
59 * So a fixed buffer in gif_struct is good enough.
60 * This buffer is only needed to copy left-over data from one GifWrite call to the next
61 */
62 #define GETN(n,s) \
63 PR_BEGIN_MACRO \
64 mGIFStruct.bytes_to_consume = (n); \
65 mGIFStruct.state = (s); \
66 PR_END_MACRO
68 /* Get a 16-bit value stored in little-endian format */
69 #define GETINT16(p) ((p)[1]<<8|(p)[0])
70 //////////////////////////////////////////////////////////////////////
71 // GIF Decoder Implementation
73 nsGIFDecoder2::nsGIFDecoder2(RasterImage &aImage)
74 : Decoder(aImage)
75 , mCurrentRow(-1)
76 , mLastFlushedRow(-1)
77 , mOldColor(0)
78 , mCurrentFrame(-1)
79 , mCurrentPass(0)
80 , mLastFlushedPass(0)
81 , mGIFOpen(false)
82 , mSawTransparency(false)
83 {
84 // Clear out the structure, excluding the arrays
85 memset(&mGIFStruct, 0, sizeof(mGIFStruct));
87 // Initialize as "animate once" in case no NETSCAPE2.0 extension is found
88 mGIFStruct.loop_count = 1;
90 // Start with the version (GIF89a|GIF87a)
91 mGIFStruct.state = gif_type;
92 mGIFStruct.bytes_to_consume = 6;
93 }
95 nsGIFDecoder2::~nsGIFDecoder2()
96 {
97 moz_free(mGIFStruct.local_colormap);
98 moz_free(mGIFStruct.hold);
99 }
101 void
102 nsGIFDecoder2::FinishInternal()
103 {
104 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call FinishInternal after error!");
106 // If the GIF got cut off, handle it anyway
107 if (!IsSizeDecode() && mGIFOpen) {
108 if (mCurrentFrame == mGIFStruct.images_decoded)
109 EndImageFrame();
110 PostDecodeDone(mGIFStruct.loop_count - 1);
111 mGIFOpen = false;
112 }
113 }
115 // Push any new rows according to mCurrentPass/mLastFlushedPass and
116 // mCurrentRow/mLastFlushedRow. Note: caller is responsible for
117 // updating mlastFlushed{Row,Pass}.
118 void
119 nsGIFDecoder2::FlushImageData(uint32_t fromRow, uint32_t rows)
120 {
121 nsIntRect r(mGIFStruct.x_offset, mGIFStruct.y_offset + fromRow, mGIFStruct.width, rows);
122 PostInvalidation(r);
123 }
125 void
126 nsGIFDecoder2::FlushImageData()
127 {
128 switch (mCurrentPass - mLastFlushedPass) {
129 case 0: // same pass
130 if (mCurrentRow - mLastFlushedRow)
131 FlushImageData(mLastFlushedRow + 1, mCurrentRow - mLastFlushedRow);
132 break;
134 case 1: // one pass on - need to handle bottom & top rects
135 FlushImageData(0, mCurrentRow + 1);
136 FlushImageData(mLastFlushedRow + 1, mGIFStruct.height - (mLastFlushedRow + 1));
137 break;
139 default: // more than one pass on - push the whole frame
140 FlushImageData(0, mGIFStruct.height);
141 }
142 }
144 //******************************************************************************
145 // GIF decoder callback methods. Part of public API for GIF2
146 //******************************************************************************
148 //******************************************************************************
149 void nsGIFDecoder2::BeginGIF()
150 {
151 if (mGIFOpen)
152 return;
154 mGIFOpen = true;
156 PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
157 }
159 //******************************************************************************
160 void nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
161 {
162 gfxImageFormat format;
163 if (mGIFStruct.is_transparent)
164 format = gfxImageFormat::ARGB32;
165 else
166 format = gfxImageFormat::RGB24;
168 MOZ_ASSERT(HasSize());
170 // Use correct format, RGB for first frame, PAL for following frames
171 // and include transparency to allow for optimization of opaque images
172 if (mGIFStruct.images_decoded) {
173 // Image data is stored with original depth and palette
174 NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
175 mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,
176 format, aDepth);
177 }
179 // Our first full frame is automatically created by the image decoding
180 // infrastructure. Just use it as long as it matches up.
181 else if (!GetCurrentFrame()->GetRect().IsEqualEdges(nsIntRect(mGIFStruct.x_offset,
182 mGIFStruct.y_offset,
183 mGIFStruct.width,
184 mGIFStruct.height))) {
185 // Regardless of depth of input, image is decoded into 24bit RGB
186 NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
187 mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,
188 format);
189 } else {
190 // Our preallocated frame matches up, with the possible exception of alpha.
191 if (format == gfxImageFormat::RGB24) {
192 GetCurrentFrame()->SetHasNoAlpha();
193 }
194 }
196 mCurrentFrame = mGIFStruct.images_decoded;
197 }
200 //******************************************************************************
201 void nsGIFDecoder2::EndImageFrame()
202 {
203 FrameBlender::FrameAlpha alpha = FrameBlender::kFrameHasAlpha;
205 // First flush all pending image data
206 if (!mGIFStruct.images_decoded) {
207 // Only need to flush first frame
208 FlushImageData();
210 // If the first frame is smaller in height than the entire image, send an
211 // invalidation for the area it does not have data for.
212 // This will clear the remaining bits of the placeholder. (Bug 37589)
213 const uint32_t realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
214 if (realFrameHeight < mGIFStruct.screen_height) {
215 nsIntRect r(0, realFrameHeight,
216 mGIFStruct.screen_width,
217 mGIFStruct.screen_height - realFrameHeight);
218 PostInvalidation(r);
219 }
220 // This transparency check is only valid for first frame
221 if (mGIFStruct.is_transparent && !mSawTransparency) {
222 alpha = FrameBlender::kFrameOpaque;
223 }
224 }
225 mCurrentRow = mLastFlushedRow = -1;
226 mCurrentPass = mLastFlushedPass = 0;
228 // Only add frame if we have any rows at all
229 if (mGIFStruct.rows_remaining != mGIFStruct.height) {
230 if (mGIFStruct.rows_remaining && mGIFStruct.images_decoded) {
231 // Clear the remaining rows (only needed for the animation frames)
232 uint8_t *rowp = mImageData + ((mGIFStruct.height - mGIFStruct.rows_remaining) * mGIFStruct.width);
233 memset(rowp, 0, mGIFStruct.rows_remaining * mGIFStruct.width);
234 }
235 }
237 // Unconditionally increment images_decoded, because we unconditionally
238 // append frames in BeginImageFrame(). This ensures that images_decoded
239 // always refers to the frame in mImage we're currently decoding,
240 // even if some of them weren't decoded properly and thus are blank.
241 mGIFStruct.images_decoded++;
243 // Tell the superclass we finished a frame
244 PostFrameStop(alpha,
245 FrameBlender::FrameDisposalMethod(mGIFStruct.disposal_method),
246 mGIFStruct.delay_time);
248 // Reset the transparent pixel
249 if (mOldColor) {
250 mColormap[mGIFStruct.tpixel] = mOldColor;
251 mOldColor = 0;
252 }
254 mCurrentFrame = -1;
255 }
258 //******************************************************************************
259 // Send the data to the display front-end.
260 uint32_t nsGIFDecoder2::OutputRow()
261 {
262 int drow_start, drow_end;
263 drow_start = drow_end = mGIFStruct.irow;
265 /* Protect against too much image data */
266 if ((unsigned)drow_start >= mGIFStruct.height) {
267 NS_WARNING("GIF2.cpp::OutputRow - too much image data");
268 return 0;
269 }
271 if (!mGIFStruct.images_decoded) {
272 /*
273 * Haeberli-inspired hack for interlaced GIFs: Replicate lines while
274 * displaying to diminish the "venetian-blind" effect as the image is
275 * loaded. Adjust pixel vertical positions to avoid the appearance of the
276 * image crawling up the screen as successive passes are drawn.
277 */
278 if (mGIFStruct.progressive_display && mGIFStruct.interlaced && (mGIFStruct.ipass < 4)) {
279 /* ipass = 1,2,3 results in resp. row_dup = 7,3,1 and row_shift = 3,1,0 */
280 const uint32_t row_dup = 15 >> mGIFStruct.ipass;
281 const uint32_t row_shift = row_dup >> 1;
283 drow_start -= row_shift;
284 drow_end = drow_start + row_dup;
286 /* Extend if bottom edge isn't covered because of the shift upward. */
287 if (((mGIFStruct.height - 1) - drow_end) <= row_shift)
288 drow_end = mGIFStruct.height - 1;
290 /* Clamp first and last rows to upper and lower edge of image. */
291 if (drow_start < 0)
292 drow_start = 0;
293 if ((unsigned)drow_end >= mGIFStruct.height)
294 drow_end = mGIFStruct.height - 1;
295 }
297 // Row to process
298 const uint32_t bpr = sizeof(uint32_t) * mGIFStruct.width;
299 uint8_t *rowp = mImageData + (mGIFStruct.irow * bpr);
301 // Convert color indices to Cairo pixels
302 uint8_t *from = rowp + mGIFStruct.width;
303 uint32_t *to = ((uint32_t*)rowp) + mGIFStruct.width;
304 uint32_t *cmap = mColormap;
305 for (uint32_t c = mGIFStruct.width; c > 0; c--) {
306 *--to = cmap[*--from];
307 }
309 // check for alpha (only for first frame)
310 if (mGIFStruct.is_transparent && !mSawTransparency) {
311 const uint32_t *rgb = (uint32_t*)rowp;
312 for (uint32_t i = mGIFStruct.width; i > 0; i--) {
313 if (*rgb++ == 0) {
314 mSawTransparency = true;
315 break;
316 }
317 }
318 }
320 // Duplicate rows
321 if (drow_end > drow_start) {
322 // irow is the current row filled
323 for (int r = drow_start; r <= drow_end; r++) {
324 if (r != int(mGIFStruct.irow)) {
325 memcpy(mImageData + (r * bpr), rowp, bpr);
326 }
327 }
328 }
329 }
331 mCurrentRow = drow_end;
332 mCurrentPass = mGIFStruct.ipass;
333 if (mGIFStruct.ipass == 1)
334 mLastFlushedPass = mGIFStruct.ipass; // interlaced starts at 1
336 if (!mGIFStruct.interlaced) {
337 mGIFStruct.irow++;
338 } else {
339 static const uint8_t kjump[5] = { 1, 8, 8, 4, 2 };
340 do {
341 // Row increments resp. per 8,8,4,2 rows
342 mGIFStruct.irow += kjump[mGIFStruct.ipass];
343 if (mGIFStruct.irow >= mGIFStruct.height) {
344 // Next pass starts resp. at row 4,2,1,0
345 mGIFStruct.irow = 8 >> mGIFStruct.ipass;
346 mGIFStruct.ipass++;
347 }
348 } while (mGIFStruct.irow >= mGIFStruct.height);
349 }
351 return --mGIFStruct.rows_remaining;
352 }
354 //******************************************************************************
355 /* Perform Lempel-Ziv-Welch decoding */
356 bool
357 nsGIFDecoder2::DoLzw(const uint8_t *q)
358 {
359 if (!mGIFStruct.rows_remaining)
360 return true;
362 /* Copy all the decoder state variables into locals so the compiler
363 * won't worry about them being aliased. The locals will be homed
364 * back into the GIF decoder structure when we exit.
365 */
366 int avail = mGIFStruct.avail;
367 int bits = mGIFStruct.bits;
368 int codesize = mGIFStruct.codesize;
369 int codemask = mGIFStruct.codemask;
370 int count = mGIFStruct.count;
371 int oldcode = mGIFStruct.oldcode;
372 const int clear_code = ClearCode();
373 uint8_t firstchar = mGIFStruct.firstchar;
374 int32_t datum = mGIFStruct.datum;
375 uint16_t *prefix = mGIFStruct.prefix;
376 uint8_t *stackp = mGIFStruct.stackp;
377 uint8_t *suffix = mGIFStruct.suffix;
378 uint8_t *stack = mGIFStruct.stack;
379 uint8_t *rowp = mGIFStruct.rowp;
381 uint32_t bpr = mGIFStruct.width;
382 if (!mGIFStruct.images_decoded)
383 bpr *= sizeof(uint32_t);
384 uint8_t *rowend = mImageData + (bpr * mGIFStruct.irow) + mGIFStruct.width;
386 #define OUTPUT_ROW() \
387 PR_BEGIN_MACRO \
388 if (!OutputRow()) \
389 goto END; \
390 rowp = mImageData + mGIFStruct.irow * bpr; \
391 rowend = rowp + mGIFStruct.width; \
392 PR_END_MACRO
394 for (const uint8_t* ch = q; count-- > 0; ch++)
395 {
396 /* Feed the next byte into the decoder's 32-bit input buffer. */
397 datum += ((int32_t) *ch) << bits;
398 bits += 8;
400 /* Check for underflow of decoder's 32-bit input buffer. */
401 while (bits >= codesize)
402 {
403 /* Get the leading variable-length symbol from the data stream */
404 int code = datum & codemask;
405 datum >>= codesize;
406 bits -= codesize;
408 /* Reset the dictionary to its original state, if requested */
409 if (code == clear_code) {
410 codesize = mGIFStruct.datasize + 1;
411 codemask = (1 << codesize) - 1;
412 avail = clear_code + 2;
413 oldcode = -1;
414 continue;
415 }
417 /* Check for explicit end-of-stream code */
418 if (code == (clear_code + 1)) {
419 /* end-of-stream should only appear after all image data */
420 return (mGIFStruct.rows_remaining == 0);
421 }
423 if (oldcode == -1) {
424 if (code >= MAX_BITS)
425 return false;
426 *rowp++ = suffix[code] & mColorMask; // ensure index is within colormap
427 if (rowp == rowend)
428 OUTPUT_ROW();
430 firstchar = oldcode = code;
431 continue;
432 }
434 int incode = code;
435 if (code >= avail) {
436 *stackp++ = firstchar;
437 code = oldcode;
439 if (stackp >= stack + MAX_BITS)
440 return false;
441 }
443 while (code >= clear_code)
444 {
445 if ((code >= MAX_BITS) || (code == prefix[code]))
446 return false;
448 *stackp++ = suffix[code];
449 code = prefix[code];
451 if (stackp == stack + MAX_BITS)
452 return false;
453 }
455 *stackp++ = firstchar = suffix[code];
457 /* Define a new codeword in the dictionary. */
458 if (avail < 4096) {
459 prefix[avail] = oldcode;
460 suffix[avail] = firstchar;
461 avail++;
463 /* If we've used up all the codewords of a given length
464 * increase the length of codewords by one bit, but don't
465 * exceed the specified maximum codeword size of 12 bits.
466 */
467 if (((avail & codemask) == 0) && (avail < 4096)) {
468 codesize++;
469 codemask += avail;
470 }
471 }
472 oldcode = incode;
474 /* Copy the decoded data out to the scanline buffer. */
475 do {
476 *rowp++ = *--stackp & mColorMask; // ensure index is within colormap
477 if (rowp == rowend)
478 OUTPUT_ROW();
479 } while (stackp > stack);
480 }
481 }
483 END:
485 /* Home the local copies of the GIF decoder state variables */
486 mGIFStruct.avail = avail;
487 mGIFStruct.bits = bits;
488 mGIFStruct.codesize = codesize;
489 mGIFStruct.codemask = codemask;
490 mGIFStruct.count = count;
491 mGIFStruct.oldcode = oldcode;
492 mGIFStruct.firstchar = firstchar;
493 mGIFStruct.datum = datum;
494 mGIFStruct.stackp = stackp;
495 mGIFStruct.rowp = rowp;
497 return true;
498 }
500 /**
501 * Expand the colormap from RGB to Packed ARGB as needed by Cairo.
502 * And apply any LCMS transformation.
503 */
504 static void ConvertColormap(uint32_t *aColormap, uint32_t aColors)
505 {
506 // Apply CMS transformation if enabled and available
507 if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
508 qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
509 if (transform)
510 qcms_transform_data(transform, aColormap, aColormap, aColors);
511 }
512 // Convert from the GIF's RGB format to the Cairo format.
513 // Work from end to begin, because of the in-place expansion
514 uint8_t *from = ((uint8_t *)aColormap) + 3 * aColors;
515 uint32_t *to = aColormap + aColors;
517 // Convert color entries to Cairo format
519 // set up for loops below
520 if (!aColors) return;
521 uint32_t c = aColors;
523 // copy as bytes until source pointer is 32-bit-aligned
524 // NB: can't use 32-bit reads, they might read off the end of the buffer
525 for (; (NS_PTR_TO_UINT32(from) & 0x3) && c; --c) {
526 from -= 3;
527 *--to = gfxPackedPixel(0xFF, from[0], from[1], from[2]);
528 }
530 // bulk copy of pixels.
531 while (c >= 4) {
532 from -= 12;
533 to -= 4;
534 c -= 4;
535 GFX_BLOCK_RGB_TO_FRGB(from,to);
536 }
538 // copy remaining pixel(s)
539 // NB: can't use 32-bit reads, they might read off the end of the buffer
540 while (c--) {
541 from -= 3;
542 *--to = gfxPackedPixel(0xFF, from[0], from[1], from[2]);
543 }
544 }
546 void
547 nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount, DecodeStrategy)
548 {
549 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
551 // These variables changed names, and renaming would make a much bigger patch :(
552 const uint8_t *buf = (const uint8_t *)aBuffer;
553 uint32_t len = aCount;
555 const uint8_t *q = buf;
557 // Add what we have sofar to the block
558 // If previous call to me left something in the hold first complete current block
559 // Or if we are filling the colormaps, first complete the colormap
560 uint8_t* p = (mGIFStruct.state == gif_global_colormap) ? (uint8_t*)mGIFStruct.global_colormap :
561 (mGIFStruct.state == gif_image_colormap) ? (uint8_t*)mColormap :
562 (mGIFStruct.bytes_in_hold) ? mGIFStruct.hold : nullptr;
564 if (len == 0 && buf == nullptr) {
565 // We've just gotten the frame we asked for. Time to use the data we
566 // stashed away.
567 len = mGIFStruct.bytes_in_hold;
568 q = buf = p;
569 } else if (p) {
570 // Add what we have sofar to the block
571 uint32_t l = std::min(len, mGIFStruct.bytes_to_consume);
572 memcpy(p+mGIFStruct.bytes_in_hold, buf, l);
574 if (l < mGIFStruct.bytes_to_consume) {
575 // Not enough in 'buf' to complete current block, get more
576 mGIFStruct.bytes_in_hold += l;
577 mGIFStruct.bytes_to_consume -= l;
578 return;
579 }
580 // Point 'q' to complete block in hold (or in colormap)
581 q = p;
582 }
584 // Invariant:
585 // 'q' is start of current to be processed block (hold, colormap or buf)
586 // 'bytes_to_consume' is number of bytes to consume from 'buf'
587 // 'buf' points to the bytes to be consumed from the input buffer
588 // 'len' is number of bytes left in input buffer from position 'buf'.
589 // At entrance of the for loop will 'buf' will be moved 'bytes_to_consume'
590 // to point to next buffer, 'len' is adjusted accordingly.
591 // So that next round in for loop, q gets pointed to the next buffer.
593 for (;len >= mGIFStruct.bytes_to_consume; q=buf, mGIFStruct.bytes_in_hold = 0) {
594 // Eat the current block from the buffer, q keeps pointed at current block
595 buf += mGIFStruct.bytes_to_consume;
596 len -= mGIFStruct.bytes_to_consume;
598 switch (mGIFStruct.state)
599 {
600 case gif_lzw:
601 if (!DoLzw(q)) {
602 mGIFStruct.state = gif_error;
603 break;
604 }
605 GETN(1, gif_sub_block);
606 break;
608 case gif_lzw_start:
609 {
610 // Make sure the transparent pixel is transparent in the colormap
611 if (mGIFStruct.is_transparent) {
612 // Save old value so we can restore it later
613 if (mColormap == mGIFStruct.global_colormap)
614 mOldColor = mColormap[mGIFStruct.tpixel];
615 mColormap[mGIFStruct.tpixel] = 0;
616 }
618 /* Initialize LZW parser/decoder */
619 mGIFStruct.datasize = *q;
620 const int clear_code = ClearCode();
621 if (mGIFStruct.datasize > MAX_LZW_BITS ||
622 clear_code >= MAX_BITS) {
623 mGIFStruct.state = gif_error;
624 break;
625 }
627 mGIFStruct.avail = clear_code + 2;
628 mGIFStruct.oldcode = -1;
629 mGIFStruct.codesize = mGIFStruct.datasize + 1;
630 mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
631 mGIFStruct.datum = mGIFStruct.bits = 0;
633 /* init the tables */
634 for (int i = 0; i < clear_code; i++)
635 mGIFStruct.suffix[i] = i;
637 mGIFStruct.stackp = mGIFStruct.stack;
639 GETN(1, gif_sub_block);
640 }
641 break;
643 /* All GIF files begin with "GIF87a" or "GIF89a" */
644 case gif_type:
645 if (!strncmp((char*)q, "GIF89a", 6)) {
646 mGIFStruct.version = 89;
647 } else if (!strncmp((char*)q, "GIF87a", 6)) {
648 mGIFStruct.version = 87;
649 } else {
650 mGIFStruct.state = gif_error;
651 break;
652 }
653 GETN(7, gif_global_header);
654 break;
656 case gif_global_header:
657 /* This is the height and width of the "screen" or
658 * frame into which images are rendered. The
659 * individual images can be smaller than the
660 * screen size and located with an origin anywhere
661 * within the screen.
662 */
664 mGIFStruct.screen_width = GETINT16(q);
665 mGIFStruct.screen_height = GETINT16(q + 2);
666 mGIFStruct.global_colormap_depth = (q[4]&0x07) + 1;
668 if (IsSizeDecode()) {
669 MOZ_ASSERT(!mGIFOpen, "Gif should not be open at this point");
670 PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height);
671 return;
672 }
674 // screen_bgcolor is not used
675 //mGIFStruct.screen_bgcolor = q[5];
676 // q[6] = Pixel Aspect Ratio
677 // Not used
678 // float aspect = (float)((q[6] + 15) / 64.0);
680 if (q[4] & 0x80) { /* global map */
681 // Get the global colormap
682 const uint32_t size = (3 << mGIFStruct.global_colormap_depth);
683 if (len < size) {
684 // Use 'hold' pattern to get the global colormap
685 GETN(size, gif_global_colormap);
686 break;
687 }
688 // Copy everything, go to colormap state to do CMS correction
689 memcpy(mGIFStruct.global_colormap, buf, size);
690 buf += size;
691 len -= size;
692 GETN(0, gif_global_colormap);
693 break;
694 }
696 GETN(1, gif_image_start);
697 break;
699 case gif_global_colormap:
700 // Everything is already copied into global_colormap
701 // Convert into Cairo colors including CMS transformation
702 ConvertColormap(mGIFStruct.global_colormap, 1<<mGIFStruct.global_colormap_depth);
703 GETN(1, gif_image_start);
704 break;
706 case gif_image_start:
707 switch (*q) {
708 case GIF_TRAILER:
709 mGIFStruct.state = gif_done;
710 break;
712 case GIF_EXTENSION_INTRODUCER:
713 GETN(2, gif_extension);
714 break;
716 case GIF_IMAGE_SEPARATOR:
717 GETN(9, gif_image_header);
718 break;
720 default:
721 /* If we get anything other than GIF_IMAGE_SEPARATOR,
722 * GIF_EXTENSION_INTRODUCER, or GIF_TRAILER, there is extraneous data
723 * between blocks. The GIF87a spec tells us to keep reading
724 * until we find an image separator, but GIF89a says such
725 * a file is corrupt. We follow GIF89a and bail out. */
726 if (mGIFStruct.images_decoded > 0) {
727 /* The file is corrupt, but one or more images have
728 * been decoded correctly. In this case, we proceed
729 * as if the file were correctly terminated and set
730 * the state to gif_done, so the GIF will display.
731 */
732 mGIFStruct.state = gif_done;
733 } else {
734 /* No images decoded, there is nothing to display. */
735 mGIFStruct.state = gif_error;
736 }
737 }
738 break;
740 case gif_extension:
741 mGIFStruct.bytes_to_consume = q[1];
742 if (mGIFStruct.bytes_to_consume) {
743 switch (*q) {
744 case GIF_GRAPHIC_CONTROL_LABEL:
745 // The GIF spec mandates that the GIFControlExtension header block length is 4 bytes,
746 // and the parser for this block reads 4 bytes, so we must enforce that the buffer
747 // contains at least this many bytes. If the GIF specifies a different length, we
748 // allow that, so long as it's larger; the additional data will simply be ignored.
749 mGIFStruct.state = gif_control_extension;
750 mGIFStruct.bytes_to_consume = std::max(mGIFStruct.bytes_to_consume, 4u);
751 break;
753 // The GIF spec also specifies the lengths of the following two extensions' headers
754 // (as 12 and 11 bytes, respectively). Because we ignore the plain text extension entirely
755 // and sanity-check the actual length of the application extension header before reading it,
756 // we allow GIFs to deviate from these values in either direction. This is important for
757 // real-world compatibility, as GIFs in the wild exist with application extension headers
758 // that are both shorter and longer than 11 bytes.
759 case GIF_APPLICATION_EXTENSION_LABEL:
760 mGIFStruct.state = gif_application_extension;
761 break;
763 case GIF_PLAIN_TEXT_LABEL:
764 mGIFStruct.state = gif_skip_block;
765 break;
767 case GIF_COMMENT_LABEL:
768 mGIFStruct.state = gif_consume_comment;
769 break;
771 default:
772 mGIFStruct.state = gif_skip_block;
773 }
774 } else {
775 GETN(1, gif_image_start);
776 }
777 break;
779 case gif_consume_block:
780 if (!*q)
781 GETN(1, gif_image_start);
782 else
783 GETN(*q, gif_skip_block);
784 break;
786 case gif_skip_block:
787 GETN(1, gif_consume_block);
788 break;
790 case gif_control_extension:
791 mGIFStruct.is_transparent = *q & 0x1;
792 mGIFStruct.tpixel = q[3];
793 mGIFStruct.disposal_method = ((*q) >> 2) & 0x7;
794 // Some specs say 3rd bit (value 4), other specs say value 3
795 // Let's choose 3 (the more popular)
796 if (mGIFStruct.disposal_method == 4)
797 mGIFStruct.disposal_method = 3;
798 mGIFStruct.delay_time = GETINT16(q + 1) * 10;
799 GETN(1, gif_consume_block);
800 break;
802 case gif_comment_extension:
803 if (*q)
804 GETN(*q, gif_consume_comment);
805 else
806 GETN(1, gif_image_start);
807 break;
809 case gif_consume_comment:
810 GETN(1, gif_comment_extension);
811 break;
813 case gif_application_extension:
814 /* Check for netscape application extension */
815 if (mGIFStruct.bytes_to_consume == 11 &&
816 (!strncmp((char*)q, "NETSCAPE2.0", 11) ||
817 !strncmp((char*)q, "ANIMEXTS1.0", 11)))
818 GETN(1, gif_netscape_extension_block);
819 else
820 GETN(1, gif_consume_block);
821 break;
823 /* Netscape-specific GIF extension: animation looping */
824 case gif_netscape_extension_block:
825 if (*q)
826 // We might need to consume 3 bytes in
827 // gif_consume_netscape_extension, so make sure we have at least that.
828 GETN(std::max(3, static_cast<int>(*q)), gif_consume_netscape_extension);
829 else
830 GETN(1, gif_image_start);
831 break;
833 /* Parse netscape-specific application extensions */
834 case gif_consume_netscape_extension:
835 switch (q[0] & 7) {
836 case 1:
837 /* Loop entire animation specified # of times. Only read the
838 loop count during the first iteration. */
839 mGIFStruct.loop_count = GETINT16(q + 1);
840 GETN(1, gif_netscape_extension_block);
841 break;
843 case 2:
844 /* Wait for specified # of bytes to enter buffer */
845 // Don't do this, this extension doesn't exist (isn't used at all)
846 // and doesn't do anything, as our streaming/buffering takes care of it all...
847 // See: http://semmix.pl/color/exgraf/eeg24.htm
848 GETN(1, gif_netscape_extension_block);
849 break;
851 default:
852 // 0,3-7 are yet to be defined netscape extension codes
853 mGIFStruct.state = gif_error;
854 }
855 break;
857 case gif_image_header:
858 {
859 /* Get image offsets, with respect to the screen origin */
860 mGIFStruct.x_offset = GETINT16(q);
861 mGIFStruct.y_offset = GETINT16(q + 2);
863 /* Get image width and height. */
864 mGIFStruct.width = GETINT16(q + 4);
865 mGIFStruct.height = GETINT16(q + 6);
867 if (!mGIFStruct.images_decoded) {
868 /* Work around broken GIF files where the logical screen
869 * size has weird width or height. We assume that GIF87a
870 * files don't contain animations.
871 */
872 if ((mGIFStruct.screen_height < mGIFStruct.height) ||
873 (mGIFStruct.screen_width < mGIFStruct.width) ||
874 (mGIFStruct.version == 87)) {
875 mGIFStruct.screen_height = mGIFStruct.height;
876 mGIFStruct.screen_width = mGIFStruct.width;
877 mGIFStruct.x_offset = 0;
878 mGIFStruct.y_offset = 0;
879 }
880 // Create the image container with the right size.
881 BeginGIF();
882 if (HasError()) {
883 // Setting the size led to an error.
884 mGIFStruct.state = gif_error;
885 return;
886 }
888 // If we were doing a size decode, we're done
889 if (IsSizeDecode())
890 return;
891 }
893 /* Work around more broken GIF files that have zero image
894 width or height */
895 if (!mGIFStruct.height || !mGIFStruct.width) {
896 mGIFStruct.height = mGIFStruct.screen_height;
897 mGIFStruct.width = mGIFStruct.screen_width;
898 if (!mGIFStruct.height || !mGIFStruct.width) {
899 mGIFStruct.state = gif_error;
900 break;
901 }
902 }
904 /* Depth of colors is determined by colormap */
905 /* (q[8] & 0x80) indicates local colormap */
906 /* bits per pixel is (q[8]&0x07 + 1) when local colormap is set */
907 uint32_t depth = mGIFStruct.global_colormap_depth;
908 if (q[8] & 0x80)
909 depth = (q[8]&0x07) + 1;
910 uint32_t realDepth = depth;
911 while (mGIFStruct.tpixel >= (1 << realDepth) && (realDepth < 8)) {
912 realDepth++;
913 }
914 // Mask to limit the color values within the colormap
915 mColorMask = 0xFF >> (8 - realDepth);
916 BeginImageFrame(realDepth);
918 if (NeedsNewFrame()) {
919 // We now need a new frame from the decoder framework. We leave all our
920 // data in the buffer as if it wasn't consumed, copy to our hold and return
921 // to the decoder framework.
922 uint32_t size = len + mGIFStruct.bytes_to_consume + mGIFStruct.bytes_in_hold;
923 if (size) {
924 if (SetHold(q, mGIFStruct.bytes_to_consume + mGIFStruct.bytes_in_hold, buf, len)) {
925 // Back into the decoder infrastructure so we can get called again.
926 GETN(9, gif_image_header_continue);
927 return;
928 }
929 }
930 break;
931 } else {
932 // FALL THROUGH
933 }
934 }
936 case gif_image_header_continue:
937 {
938 // While decoders can reuse frames, we unconditionally increment
939 // mGIFStruct.images_decoded when we're done with a frame, so we both can
940 // and need to zero out the colormap and image data after every new frame.
941 memset(mImageData, 0, mImageDataLength);
942 if (mColormap) {
943 memset(mColormap, 0, mColormapSize);
944 }
946 if (!mGIFStruct.images_decoded) {
947 // Send a onetime invalidation for the first frame if it has a y-axis offset.
948 // Otherwise, the area may never be refreshed and the placeholder will remain
949 // on the screen. (Bug 37589)
950 if (mGIFStruct.y_offset > 0) {
951 nsIntRect r(0, 0, mGIFStruct.screen_width, mGIFStruct.y_offset);
952 PostInvalidation(r);
953 }
954 }
956 if (q[8] & 0x40) {
957 mGIFStruct.interlaced = true;
958 mGIFStruct.ipass = 1;
959 } else {
960 mGIFStruct.interlaced = false;
961 mGIFStruct.ipass = 0;
962 }
964 /* Only apply the Haeberli display hack on the first frame */
965 mGIFStruct.progressive_display = (mGIFStruct.images_decoded == 0);
967 /* Clear state from last image */
968 mGIFStruct.irow = 0;
969 mGIFStruct.rows_remaining = mGIFStruct.height;
970 mGIFStruct.rowp = mImageData;
972 /* Depth of colors is determined by colormap */
973 /* (q[8] & 0x80) indicates local colormap */
974 /* bits per pixel is (q[8]&0x07 + 1) when local colormap is set */
975 uint32_t depth = mGIFStruct.global_colormap_depth;
976 if (q[8] & 0x80)
977 depth = (q[8]&0x07) + 1;
978 uint32_t realDepth = depth;
979 while (mGIFStruct.tpixel >= (1 << realDepth) && (realDepth < 8)) {
980 realDepth++;
981 }
983 if (q[8] & 0x80) /* has a local colormap? */
984 {
985 mGIFStruct.local_colormap_size = 1 << depth;
986 if (!mGIFStruct.images_decoded) {
987 // First frame has local colormap, allocate space for it
988 // as the image frame doesn't have its own palette
989 mColormapSize = sizeof(uint32_t) << realDepth;
990 if (!mGIFStruct.local_colormap) {
991 mGIFStruct.local_colormap = (uint32_t*)moz_xmalloc(mColormapSize);
992 }
993 mColormap = mGIFStruct.local_colormap;
994 }
995 const uint32_t size = 3 << depth;
996 if (mColormapSize > size) {
997 // Clear the notfilled part of the colormap
998 memset(((uint8_t*)mColormap) + size, 0, mColormapSize - size);
999 }
1000 if (len < size) {
1001 // Use 'hold' pattern to get the image colormap
1002 GETN(size, gif_image_colormap);
1003 break;
1004 }
1005 // Copy everything, go to colormap state to do CMS correction
1006 memcpy(mColormap, buf, size);
1007 buf += size;
1008 len -= size;
1009 GETN(0, gif_image_colormap);
1010 break;
1011 } else {
1012 /* Switch back to the global palette */
1013 if (mGIFStruct.images_decoded) {
1014 // Copy global colormap into the palette of current frame
1015 memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
1016 } else {
1017 mColormap = mGIFStruct.global_colormap;
1018 }
1019 }
1020 GETN(1, gif_lzw_start);
1021 }
1022 break;
1024 case gif_image_colormap:
1025 // Everything is already copied into local_colormap
1026 // Convert into Cairo colors including CMS transformation
1027 ConvertColormap(mColormap, mGIFStruct.local_colormap_size);
1028 GETN(1, gif_lzw_start);
1029 break;
1031 case gif_sub_block:
1032 mGIFStruct.count = *q;
1033 if (mGIFStruct.count) {
1034 /* Still working on the same image: Process next LZW data block */
1035 /* Make sure there are still rows left. If the GIF data */
1036 /* is corrupt, we may not get an explicit terminator. */
1037 if (!mGIFStruct.rows_remaining) {
1038 #ifdef DONT_TOLERATE_BROKEN_GIFS
1039 mGIFStruct.state = gif_error;
1040 break;
1041 #else
1042 /* This is an illegal GIF, but we remain tolerant. */
1043 GETN(1, gif_sub_block);
1044 #endif
1045 if (mGIFStruct.count == GIF_TRAILER) {
1046 /* Found a terminator anyway, so consider the image done */
1047 GETN(1, gif_done);
1048 break;
1049 }
1050 }
1051 GETN(mGIFStruct.count, gif_lzw);
1052 } else {
1053 /* See if there are any more images in this sequence. */
1054 EndImageFrame();
1055 GETN(1, gif_image_start);
1056 }
1057 break;
1059 case gif_done:
1060 MOZ_ASSERT(!IsSizeDecode(), "Size decodes shouldn't reach gif_done");
1061 FinishInternal();
1062 goto done;
1064 case gif_error:
1065 PostDataError();
1066 return;
1068 // We shouldn't ever get here.
1069 default:
1070 break;
1071 }
1072 }
1074 // if an error state is set but no data remains, code flow reaches here
1075 if (mGIFStruct.state == gif_error) {
1076 PostDataError();
1077 return;
1078 }
1080 // Copy the leftover into mGIFStruct.hold
1081 if (len) {
1082 // Add what we have sofar to the block
1083 if (mGIFStruct.state != gif_global_colormap && mGIFStruct.state != gif_image_colormap) {
1084 if (!SetHold(buf, len)) {
1085 PostDataError();
1086 return;
1087 }
1088 } else {
1089 uint8_t* p = (mGIFStruct.state == gif_global_colormap) ? (uint8_t*)mGIFStruct.global_colormap :
1090 (uint8_t*)mColormap;
1091 memcpy(p, buf, len);
1092 mGIFStruct.bytes_in_hold = len;
1093 }
1095 mGIFStruct.bytes_to_consume -= len;
1096 }
1098 // We want to flush before returning if we're on the first frame
1099 done:
1100 if (!mGIFStruct.images_decoded) {
1101 FlushImageData();
1102 mLastFlushedRow = mCurrentRow;
1103 mLastFlushedPass = mCurrentPass;
1104 }
1106 return;
1107 }
1109 bool
1110 nsGIFDecoder2::SetHold(const uint8_t* buf1, uint32_t count1, const uint8_t* buf2 /* = nullptr */, uint32_t count2 /* = 0 */)
1111 {
1112 // We have to handle the case that buf currently points to hold
1113 uint8_t* newHold = (uint8_t *) moz_malloc(std::max(uint32_t(MIN_HOLD_SIZE), count1 + count2));
1114 if (!newHold) {
1115 mGIFStruct.state = gif_error;
1116 return false;
1117 }
1119 memcpy(newHold, buf1, count1);
1120 if (buf2) {
1121 memcpy(newHold + count1, buf2, count2);
1122 }
1124 moz_free(mGIFStruct.hold);
1125 mGIFStruct.hold = newHold;
1126 mGIFStruct.bytes_in_hold = count1 + count2;
1127 return true;
1128 }
1130 Telemetry::ID
1131 nsGIFDecoder2::SpeedHistogram()
1132 {
1133 return Telemetry::IMAGE_DECODE_SPEED_GIF;
1134 }
1137 } // namespace image
1138 } // namespace mozilla