LexerTransition<nsIconDecoder::State>
nsIconDecoder::Finish()
{
  PostFrameStop();
  PostDecodeDone();

  return Transition::TerminateSuccess();
}
Exemple #2
0
void
Decoder::CompleteDecode()
{
  // Implementation-specific finalization
  BeforeFinishInternal();
  if (!HasError()) {
    FinishInternal();
  } else {
    FinishWithErrorInternal();
  }

  // If the implementation left us mid-frame, finish that up.
  if (mInFrame && !HasError()) {
    PostFrameStop();
  }

  // If PostDecodeDone() has not been called, and this decoder wasn't aborted
  // early because of low-memory conditions or losing a race with another
  // decoder, we need to send teardown notifications (and report an error to the
  // console later).
  if (!IsMetadataDecode() && !mDecodeDone && !WasAborted()) {
    mShouldReportError = true;

    // If we only have a data error, we're usable if we have at least one
    // complete frame.
    if (!HasDecoderError() && GetCompleteFrameCount() > 0) {
      // We're usable, so do exactly what we should have when the decoder
      // completed.

      // Not writing to the entire frame may have left us transparent.
      PostHasTransparency();

      if (mInFrame) {
        PostFrameStop();
      }
      PostDecodeDone();
    } else {
      // We're not usable. Record some final progress indicating the error.
      if (!IsMetadataDecode()) {
        mProgress |= FLAG_DECODE_COMPLETE;
      }
      mProgress |= FLAG_HAS_ERROR;
    }
  }

  if (mDecodeDone && !IsMetadataDecode()) {
    MOZ_ASSERT(HasError() || mCurrentFrame, "Should have an error or a frame");

    // If this image wasn't animated and isn't a transient image, mark its frame
    // as optimizable. We don't support optimizing animated images and
    // optimizing transient images isn't worth it.
    if (!HasAnimation() &&
        !(mDecoderFlags & DecoderFlags::IMAGE_IS_TRANSIENT) &&
        mCurrentFrame) {
      mCurrentFrame->SetOptimizable();
    }
  }
}
Exemple #3
0
void
nsWEBPDecoder::FinishInternal()
{
  // Flush the Decoder and let it free the output image buffer.
  WebPIDelete(mDecoder);
  WebPFreeDecBuffer(&mDecBuf);

  // We should never make multiple frames
  MOZ_ASSERT(GetFrameCount() <= 1, "Multiple WebP frames?");

  // Send notifications if appropriate
  if (!IsSizeDecode() && (GetFrameCount() == 1)) {
    PostFrameStop();
    PostDecodeDone();
  }
}
void
nsJPEGDecoder::NotifyDone()
{
  PostFrameStop(FrameBlender::kFrameOpaque);
  PostDecodeDone();
}
void
nsJPEGDecoder::NotifyDone()
{
  PostFrameStop(Opacity::OPAQUE);
  PostDecodeDone();
}
Exemple #6
0
void
Decoder::Finish(RasterImage::eShutdownIntent aShutdownIntent)
{
  // Implementation-specific finalization
  if (!HasError())
    FinishInternal();

  // If the implementation left us mid-frame, finish that up.
  if (mInFrame && !HasError())
    PostFrameStop();

  // If PostDecodeDone() has not been called, we need to sent teardown
  // notifications.
  if (!IsSizeDecode() && !mDecodeDone) {

    // Log data errors to the error console
    nsCOMPtr<nsIConsoleService> consoleService =
      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    nsCOMPtr<nsIScriptError> errorObject =
      do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);

    if (consoleService && errorObject && !HasDecoderError()) {
      nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") +
                       NS_ConvertUTF8toUTF16(mImage.GetURIString()));

      if (NS_SUCCEEDED(errorObject->InitWithWindowID(
                         msg,
                         NS_ConvertUTF8toUTF16(mImage.GetURIString()),
                         EmptyString(), 0, 0, nsIScriptError::errorFlag,
                         "Image", mImage.InnerWindowID()
                       ))) {
        consoleService->LogMessage(errorObject);
      }
    }

    bool usable = true;
    if (aShutdownIntent != RasterImage::eShutdownIntent_NotNeeded && !HasDecoderError()) {
      // If we only have a data error, we're usable if we have at least one complete frame.
      if (GetCompleteFrameCount() == 0) {
        usable = false;
      }
    }

    // If we're usable, do exactly what we should have when the decoder
    // completed.
    if (usable) {
      if (mInFrame) {
        PostFrameStop();
      }
      PostDecodeDone();
    } else {
      if (mObserver) {
        mObserver->OnStopDecode(NS_ERROR_FAILURE);
      }
    }
  }

  // Set image metadata before calling DecodingComplete, because DecodingComplete calls Optimize().
  mImageMetadata.SetOnImage(&mImage);

  if (mDecodeDone) {
    mImage.DecodingComplete();
  }
}
void
nsIconDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
                             DecodeStrategy)
{
  NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");

  // We put this here to avoid errors about crossing initialization with case
  // jumps on linux.
  uint32_t bytesToRead = 0;

  // Loop until the input data is gone
  while (aCount > 0) {
    switch (mState) {
      case iconStateStart:

        // Grab the width
        mWidth = (uint8_t)*aBuffer;

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateHaveHeight;
        break;

      case iconStateHaveHeight:

        // Grab the Height
        mHeight = (uint8_t)*aBuffer;

        // Post our size to the superclass
        PostSize(mWidth, mHeight);

        PostHasTransparency();

        if (HasError()) {
          // Setting the size led to an error.
          mState = iconStateFinished;
          return;
        }

        // If We're doing a size decode, we're done
        if (IsSizeDecode()) {
          mState = iconStateFinished;
          break;
        }

        if (!mImageData) {
          PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
          return;
        }

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateReadPixels;
        break;

      case iconStateReadPixels: {

        // How many bytes are we reading?
        bytesToRead = std::min(aCount, mImageDataLength - mPixBytesRead);

        // Copy the bytes
        memcpy(mImageData + mPixBytesRead, aBuffer, bytesToRead);

        // Performance isn't critical here, so our update rectangle is
        // always the full icon
        nsIntRect r(0, 0, mWidth, mHeight);

        // Invalidate
        PostInvalidation(r);

        // Book Keeping
        aBuffer += bytesToRead;
        aCount -= bytesToRead;
        mPixBytesRead += bytesToRead;

        // If we've got all the pixel bytes, we're finished
        if (mPixBytesRead == mImageDataLength) {
          PostFrameStop();
          PostDecodeDone();
          mState = iconStateFinished;
        }
        break;
      }

      case iconStateFinished:

        // Consume all excess data silently
        aCount = 0;

        break;
    }
  }
}
Exemple #8
0
void
nsIconDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
{
  NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");

  // We put this here to avoid errors about crossing initialization with case
  // jumps on linux.
  PRUint32 bytesToRead = 0;
  nsresult rv;

  // Performance isn't critical here, so our update rectangle is 
  // always the full icon
  nsIntRect r(0, 0, mWidth, mHeight);

  // Loop until the input data is gone
  while (aCount > 0) {
    switch (mState) {
      case iconStateStart:

        // Grab the width
        mWidth = (PRUint8)*aBuffer;

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateHaveHeight;
        break;

      case iconStateHaveHeight:

        // Grab the Height
        mHeight = (PRUint8)*aBuffer;

        // Post our size to the superclass
        PostSize(mWidth, mHeight);
        if (HasError()) {
          // Setting the size led to an error.
          mState = iconStateFinished;
          return;
        }

        // If We're doing a size decode, we're done
        if (IsSizeDecode()) {
          mState = iconStateFinished;
          break;
        }

        // Add the frame and signal
        rv = mImage.EnsureFrame(0, 0, 0, mWidth, mHeight,
                                gfxASurface::ImageFormatARGB32,
                                &mImageData, &mPixBytesTotal);
        if (NS_FAILED(rv)) {
          PostDecoderError(rv);
          return;
        }

        // Tell the superclass we're starting a frame
        PostFrameStart();

        // Book Keeping
        aBuffer++;
        aCount--;
        mState = iconStateReadPixels;
        break;

      case iconStateReadPixels:

        // How many bytes are we reading?
        bytesToRead = NS_MIN(aCount, mPixBytesTotal - mPixBytesRead);

        // Copy the bytes
        memcpy(mImageData + mPixBytesRead, aBuffer, bytesToRead);

        // Invalidate
        PostInvalidation(r);

        // Book Keeping
        aBuffer += bytesToRead;
        aCount -= bytesToRead;
        mPixBytesRead += bytesToRead;

        // If we've got all the pixel bytes, we're finished
        if (mPixBytesRead == mPixBytesTotal) {
          PostFrameStop();
          PostDecodeDone();
          mState = iconStateFinished;
        }
        break;

      case iconStateFinished:

        // Consume all excess data silently
        aCount = 0;

        break;
    }
  }
}
Exemple #9
0
void
nsGIFDecoder2::WriteInternal(const char *aBuffer, PRUint32 aCount)
{
    NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");

    // These variables changed names, and renaming would make a much bigger patch :(
    const PRUint8 *buf = (const PRUint8 *)aBuffer;
    PRUint32 len = aCount;

    const PRUint8 *q = buf;

    // Add what we have sofar to the block
    // If previous call to me left something in the hold first complete current block
    // Or if we are filling the colormaps, first complete the colormap
    PRUint8* p = (mGIFStruct.state == gif_global_colormap) ? (PRUint8*)mGIFStruct.global_colormap :
                 (mGIFStruct.state == gif_image_colormap) ? (PRUint8*)mColormap :
                 (mGIFStruct.bytes_in_hold) ? mGIFStruct.hold : nsnull;
    if (p) {
        // Add what we have sofar to the block
        PRUint32 l = NS_MIN(len, mGIFStruct.bytes_to_consume);
        memcpy(p+mGIFStruct.bytes_in_hold, buf, l);

        if (l < mGIFStruct.bytes_to_consume) {
            // Not enough in 'buf' to complete current block, get more
            mGIFStruct.bytes_in_hold += l;
            mGIFStruct.bytes_to_consume -= l;
            return;
        }
        // Reset hold buffer count
        mGIFStruct.bytes_in_hold = 0;
        // Point 'q' to complete block in hold (or in colormap)
        q = p;
    }

    // Invariant:
    //    'q' is start of current to be processed block (hold, colormap or buf)
    //    'bytes_to_consume' is number of bytes to consume from 'buf'
    //    'buf' points to the bytes to be consumed from the input buffer
    //    'len' is number of bytes left in input buffer from position 'buf'.
    //    At entrance of the for loop will 'buf' will be moved 'bytes_to_consume'
    //    to point to next buffer, 'len' is adjusted accordingly.
    //    So that next round in for loop, q gets pointed to the next buffer.

    for (; len >= mGIFStruct.bytes_to_consume; q=buf) {
        // Eat the current block from the buffer, q keeps pointed at current block
        buf += mGIFStruct.bytes_to_consume;
        len -= mGIFStruct.bytes_to_consume;

        switch (mGIFStruct.state)
        {
        case gif_lzw:
            if (!DoLzw(q)) {
                mGIFStruct.state = gif_error;
                break;
            }
            GETN(1, gif_sub_block);
            break;

        case gif_lzw_start:
        {
            // Make sure the transparent pixel is transparent in the colormap
            if (mGIFStruct.is_transparent) {
                // Save old value so we can restore it later
                if (mColormap == mGIFStruct.global_colormap)
                    mOldColor = mColormap[mGIFStruct.tpixel];
                mColormap[mGIFStruct.tpixel] = 0;
            }

            /* Initialize LZW parser/decoder */
            mGIFStruct.datasize = *q;
            const int clear_code = ClearCode();
            if (mGIFStruct.datasize > MAX_LZW_BITS ||
                    clear_code >= MAX_BITS) {
                mGIFStruct.state = gif_error;
                break;
            }

            mGIFStruct.avail = clear_code + 2;
            mGIFStruct.oldcode = -1;
            mGIFStruct.codesize = mGIFStruct.datasize + 1;
            mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
            mGIFStruct.datum = mGIFStruct.bits = 0;

            /* init the tables */
            for (int i = 0; i < clear_code; i++)
                mGIFStruct.suffix[i] = i;

            mGIFStruct.stackp = mGIFStruct.stack;

            GETN(1, gif_sub_block);
        }
        break;

        /* All GIF files begin with "GIF87a" or "GIF89a" */
        case gif_type:
            if (!strncmp((char*)q, "GIF89a", 6)) {
                mGIFStruct.version = 89;
            } else if (!strncmp((char*)q, "GIF87a", 6)) {
                mGIFStruct.version = 87;
            } else {
                mGIFStruct.state = gif_error;
                break;
            }
            GETN(7, gif_global_header);
            break;

        case gif_global_header:
            /* This is the height and width of the "screen" or
             * frame into which images are rendered.  The
             * individual images can be smaller than the
             * screen size and located with an origin anywhere
             * within the screen.
             */

            mGIFStruct.screen_width = GETINT16(q);
            mGIFStruct.screen_height = GETINT16(q + 2);
            mGIFStruct.global_colormap_depth = (q[4]&0x07) + 1;

            // screen_bgcolor is not used
            //mGIFStruct.screen_bgcolor = q[5];
            // q[6] = Pixel Aspect Ratio
            //   Not used
            //   float aspect = (float)((q[6] + 15) / 64.0);

            if (q[4] & 0x80) { /* global map */
                // Get the global colormap
                const PRUint32 size = (3 << mGIFStruct.global_colormap_depth);
                if (len < size) {
                    // Use 'hold' pattern to get the global colormap
                    GETN(size, gif_global_colormap);
                    break;
                }
                // Copy everything, go to colormap state to do CMS correction
                memcpy(mGIFStruct.global_colormap, buf, size);
                buf += size;
                len -= size;
                GETN(0, gif_global_colormap);
                break;
            }

            GETN(1, gif_image_start);
            break;

        case gif_global_colormap:
            // Everything is already copied into global_colormap
            // Convert into Cairo colors including CMS transformation
            ConvertColormap(mGIFStruct.global_colormap, 1<<mGIFStruct.global_colormap_depth);
            GETN(1, gif_image_start);
            break;

        case gif_image_start:
            switch (*q) {
            case GIF_TRAILER:
                mGIFStruct.state = gif_done;
                break;

            case GIF_EXTENSION_INTRODUCER:
                GETN(2, gif_extension);
                break;

            case GIF_IMAGE_SEPARATOR:
                GETN(9, gif_image_header);
                break;

            default:
                /* If we get anything other than GIF_IMAGE_SEPARATOR,
                 * GIF_EXTENSION_INTRODUCER, or GIF_TRAILER, there is extraneous data
                 * between blocks. The GIF87a spec tells us to keep reading
                 * until we find an image separator, but GIF89a says such
                 * a file is corrupt. We follow GIF89a and bail out. */
                if (mGIFStruct.images_decoded > 0) {
                    /* The file is corrupt, but one or more images have
                     * been decoded correctly. In this case, we proceed
                     * as if the file were correctly terminated and set
                     * the state to gif_done, so the GIF will display.
                     */
                    mGIFStruct.state = gif_done;
                } else {
                    /* No images decoded, there is nothing to display. */
                    mGIFStruct.state = gif_error;
                }
            }
            break;

        case gif_extension:
            mGIFStruct.bytes_to_consume = q[1];
            if (mGIFStruct.bytes_to_consume) {
                switch (*q) {
                case GIF_GRAPHIC_CONTROL_LABEL:
                    mGIFStruct.state = gif_control_extension;
                    break;

                case GIF_APPLICATION_EXTENSION_LABEL:
                    mGIFStruct.state = gif_application_extension;
                    break;

                case GIF_COMMENT_LABEL:
                    mGIFStruct.state = gif_consume_comment;
                    break;

                default:
                    mGIFStruct.state = gif_skip_block;
                }
            } else {
                GETN(1, gif_image_start);
            }
            break;

        case gif_consume_block:
            if (!*q)
                GETN(1, gif_image_start);
            else
                GETN(*q, gif_skip_block);
            break;

        case gif_skip_block:
            GETN(1, gif_consume_block);
            break;

        case gif_control_extension:
            mGIFStruct.is_transparent = *q & 0x1;
            mGIFStruct.tpixel = q[3];
            mGIFStruct.disposal_method = ((*q) >> 2) & 0x7;
            // Some specs say 3rd bit (value 4), other specs say value 3
            // Let's choose 3 (the more popular)
            if (mGIFStruct.disposal_method == 4)
                mGIFStruct.disposal_method = 3;
            mGIFStruct.delay_time = GETINT16(q + 1) * 10;
            GETN(1, gif_consume_block);
            break;

        case gif_comment_extension:
            if (*q)
                GETN(*q, gif_consume_comment);
            else
                GETN(1, gif_image_start);
            break;

        case gif_consume_comment:
            GETN(1, gif_comment_extension);
            break;

        case gif_application_extension:
            /* Check for netscape application extension */
            if (!strncmp((char*)q, "NETSCAPE2.0", 11) ||
                    !strncmp((char*)q, "ANIMEXTS1.0", 11))
                GETN(1, gif_netscape_extension_block);
            else
                GETN(1, gif_consume_block);
            break;

        /* Netscape-specific GIF extension: animation looping */
        case gif_netscape_extension_block:
            if (*q)
                GETN(*q, gif_consume_netscape_extension);
            else
                GETN(1, gif_image_start);
            break;

        /* Parse netscape-specific application extensions */
        case gif_consume_netscape_extension:
            switch (q[0] & 7) {
            case 1:
                /* Loop entire animation specified # of times.  Only read the
                   loop count during the first iteration. */
                mGIFStruct.loop_count = GETINT16(q + 1);
                GETN(1, gif_netscape_extension_block);
                break;

            case 2:
                /* Wait for specified # of bytes to enter buffer */
                // Don't do this, this extension doesn't exist (isn't used at all)
                // and doesn't do anything, as our streaming/buffering takes care of it all...
                // See: http://semmix.pl/color/exgraf/eeg24.htm
                GETN(1, gif_netscape_extension_block);
                break;

            default:
                // 0,3-7 are yet to be defined netscape extension codes
                mGIFStruct.state = gif_error;
            }
            break;

        case gif_image_header:
        {
            /* Get image offsets, with respect to the screen origin */
            mGIFStruct.x_offset = GETINT16(q);
            mGIFStruct.y_offset = GETINT16(q + 2);

            /* Get image width and height. */
            mGIFStruct.width  = GETINT16(q + 4);
            mGIFStruct.height = GETINT16(q + 6);

            if (!mGIFStruct.images_decoded) {
                /* Work around broken GIF files where the logical screen
                 * size has weird width or height.  We assume that GIF87a
                 * files don't contain animations.
                 */
                if ((mGIFStruct.screen_height < mGIFStruct.height) ||
                        (mGIFStruct.screen_width < mGIFStruct.width) ||
                        (mGIFStruct.version == 87)) {
                    mGIFStruct.screen_height = mGIFStruct.height;
                    mGIFStruct.screen_width = mGIFStruct.width;
                    mGIFStruct.x_offset = 0;
                    mGIFStruct.y_offset = 0;
                }
                // Create the image container with the right size.
                BeginGIF();
                if (HasError()) {
                    // Setting the size lead to an error; this can happen when for example
                    // a multipart channel sends an image of a different size.
                    mGIFStruct.state = gif_error;
                    return;
                }

                // If we were doing a size decode, we're done
                if (IsSizeDecode())
                    return;
            }

            /* Work around more broken GIF files that have zero image
               width or height */
            if (!mGIFStruct.height || !mGIFStruct.width) {
                mGIFStruct.height = mGIFStruct.screen_height;
                mGIFStruct.width = mGIFStruct.screen_width;
                if (!mGIFStruct.height || !mGIFStruct.width) {
                    mGIFStruct.state = gif_error;
                    break;
                }
            }

            /* Depth of colors is determined by colormap */
            /* (q[8] & 0x80) indicates local colormap */
            /* bits per pixel is (q[8]&0x07 + 1) when local colormap is set */
            PRUint32 depth = mGIFStruct.global_colormap_depth;
            if (q[8] & 0x80)
                depth = (q[8]&0x07) + 1;
            PRUint32 realDepth = depth;
            while (mGIFStruct.tpixel >= (1 << realDepth) && (realDepth < 8)) {
                realDepth++;
            }
            // Mask to limit the color values within the colormap
            mColorMask = 0xFF >> (8 - realDepth);
            nsresult rv = BeginImageFrame(realDepth);
            if (NS_FAILED(rv) || !mImageData) {
                mGIFStruct.state = gif_error;
                break;
            }

            if (q[8] & 0x40) {
                mGIFStruct.interlaced = PR_TRUE;
                mGIFStruct.ipass = 1;
            } else {
                mGIFStruct.interlaced = PR_FALSE;
                mGIFStruct.ipass = 0;
            }

            /* Only apply the Haeberli display hack on the first frame */
            mGIFStruct.progressive_display = (mGIFStruct.images_decoded == 0);

            /* Clear state from last image */
            mGIFStruct.irow = 0;
            mGIFStruct.rows_remaining = mGIFStruct.height;
            mGIFStruct.rowp = mImageData;

            /* bits per pixel is q[8]&0x07 */

            if (q[8] & 0x80) /* has a local colormap? */
            {
                mGIFStruct.local_colormap_size = 1 << depth;
                if (!mGIFStruct.images_decoded) {
                    // First frame has local colormap, allocate space for it
                    // as the image frame doesn't have its own palette
                    mColormapSize = sizeof(PRUint32) << realDepth;
                    if (!mGIFStruct.local_colormap) {
                        mGIFStruct.local_colormap = (PRUint32*)moz_xmalloc(mColormapSize);
                    }
                    mColormap = mGIFStruct.local_colormap;
                }
                const PRUint32 size = 3 << depth;
                if (mColormapSize > size) {
                    // Clear the notfilled part of the colormap
                    memset(((PRUint8*)mColormap) + size, 0, mColormapSize - size);
                }
                if (len < size) {
                    // Use 'hold' pattern to get the image colormap
                    GETN(size, gif_image_colormap);
                    break;
                }
                // Copy everything, go to colormap state to do CMS correction
                memcpy(mColormap, buf, size);
                buf += size;
                len -= size;
                GETN(0, gif_image_colormap);
                break;
            } else {
                /* Switch back to the global palette */
                if (mGIFStruct.images_decoded) {
                    // Copy global colormap into the palette of current frame
                    memcpy(mColormap, mGIFStruct.global_colormap, mColormapSize);
                } else {
                    mColormap = mGIFStruct.global_colormap;
                }
            }
            GETN(1, gif_lzw_start);
        }
        break;

        case gif_image_colormap:
            // Everything is already copied into local_colormap
            // Convert into Cairo colors including CMS transformation
            ConvertColormap(mColormap, mGIFStruct.local_colormap_size);
            GETN(1, gif_lzw_start);
            break;

        case gif_sub_block:
            mGIFStruct.count = *q;
            if (mGIFStruct.count) {
                /* Still working on the same image: Process next LZW data block */
                /* Make sure there are still rows left. If the GIF data */
                /* is corrupt, we may not get an explicit terminator.   */
                if (!mGIFStruct.rows_remaining) {
#ifdef DONT_TOLERATE_BROKEN_GIFS
                    mGIFStruct.state = gif_error;
                    break;
#else
                    /* This is an illegal GIF, but we remain tolerant. */
                    GETN(1, gif_sub_block);
#endif
                    if (mGIFStruct.count == GIF_TRAILER) {
                        /* Found a terminator anyway, so consider the image done */
                        GETN(1, gif_done);
                        break;
                    }
                }
                GETN(mGIFStruct.count, gif_lzw);
            } else {
                /* See if there are any more images in this sequence. */
                EndImageFrame();
                GETN(1, gif_image_start);
            }
            break;

        case gif_done:
            PostDecodeDone();
            mGIFOpen = PR_FALSE;
            goto done;

        case gif_error:
            PostDataError();
            return;

        // We shouldn't ever get here.
        default:
            break;
        }
    }

    // if an error state is set but no data remains, code flow reaches here
    if (mGIFStruct.state == gif_error) {
        PostDataError();
        return;
    }

    // Copy the leftover into mGIFStruct.hold
    mGIFStruct.bytes_in_hold = len;
    if (len) {
        // Add what we have sofar to the block
        PRUint8* p = (mGIFStruct.state == gif_global_colormap) ? (PRUint8*)mGIFStruct.global_colormap :
                     (mGIFStruct.state == gif_image_colormap) ? (PRUint8*)mColormap :
                     mGIFStruct.hold;
        memcpy(p, buf, len);
        mGIFStruct.bytes_to_consume -= len;
    }

// We want to flush before returning if we're on the first frame
done:
    if (!mGIFStruct.images_decoded) {
        FlushImageData();
        mLastFlushedRow = mCurrentRow;
        mLastFlushedPass = mCurrentPass;
    }

    return;
}
void
nsJPEGDecoder::NotifyDone()
{
  PostFrameStop();
  PostDecodeDone();
}
Exemple #11
0
void
Decoder::Finish(ShutdownReason aReason)
{
  MOZ_ASSERT(NS_IsMainThread());

  // Implementation-specific finalization
  if (!HasError())
    FinishInternal();

  // If the implementation left us mid-frame, finish that up.
  if (mInFrame && !HasError())
    PostFrameStop();

  // If PostDecodeDone() has not been called, we need to sent teardown
  // notifications.
  if (!IsSizeDecode() && !mDecodeDone) {

    // Log data errors to the error console
    nsCOMPtr<nsIConsoleService> consoleService =
      do_GetService(NS_CONSOLESERVICE_CONTRACTID);
    nsCOMPtr<nsIScriptError> errorObject =
      do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);

    if (consoleService && errorObject && !HasDecoderError()) {
      nsAutoString msg(NS_LITERAL_STRING("Image corrupt or truncated: ") +
                       NS_ConvertUTF8toUTF16(mImage.GetURIString()));

      if (NS_SUCCEEDED(errorObject->InitWithWindowID(
                         msg,
                         NS_ConvertUTF8toUTF16(mImage.GetURIString()),
                         EmptyString(), 0, 0, nsIScriptError::errorFlag,
                         "Image", mImage.InnerWindowID()
                       ))) {
        consoleService->LogMessage(errorObject);
      }
    }

    bool usable = !HasDecoderError();
    if (aReason != ShutdownReason::NOT_NEEDED && !HasDecoderError()) {
      // If we only have a data error, we're usable if we have at least one complete frame.
      if (GetCompleteFrameCount() == 0) {
        usable = false;
      }
    }

    // If we're usable, do exactly what we should have when the decoder
    // completed.
    if (usable) {
      if (mInFrame) {
        PostFrameStop();
      }
      PostDecodeDone();
    } else {
      if (!IsSizeDecode()) {
        mProgress |= FLAG_DECODE_COMPLETE | FLAG_ONLOAD_UNBLOCKED;
      }
      mProgress |= FLAG_HAS_ERROR;
    }
  }

  // Set image metadata before calling DecodingComplete, because
  // DecodingComplete calls Optimize().
  mImageMetadata.SetOnImage(&mImage);

  if (mDecodeDone) {
    MOZ_ASSERT(HasError() || mCurrentFrame, "Should have an error or a frame");
    mImage.DecodingComplete(mCurrentFrame.get());
  }
}