image/decoders/nsGIFDecoder2.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

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;
  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;
  1020       GETN(1, gif_lzw_start);
  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;
  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);
  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;
  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;
  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;
  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;
  1095     mGIFStruct.bytes_to_consume -= len;
  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;
  1106   return;
  1109 bool
  1110 nsGIFDecoder2::SetHold(const uint8_t* buf1, uint32_t count1, const uint8_t* buf2 /* = nullptr */, uint32_t count2 /* = 0 */)
  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;
  1119   memcpy(newHold, buf1, count1);
  1120   if (buf2) {
  1121     memcpy(newHold + count1, buf2, count2);
  1124   moz_free(mGIFStruct.hold);
  1125   mGIFStruct.hold = newHold;
  1126   mGIFStruct.bytes_in_hold = count1 + count2;
  1127   return true;
  1130 Telemetry::ID
  1131 nsGIFDecoder2::SpeedHistogram()
  1133   return Telemetry::IMAGE_DECODE_SPEED_GIF;
  1137 } // namespace image
  1138 } // namespace mozilla

mercurial