зеркало из https://github.com/mozilla/gecko-dev.git
Bug 716140 - Make animated image formats (PNG and GIF) explicitly pause decoding and ask for a new image frame when they need new frames.
--HG-- extra : rebase_source : 3a4148d8d144784075ec88668359c333420c3d4a
This commit is contained in:
Родитель
4d3a7dae17
Коммит
3a1ba4d188
|
@ -8,7 +8,7 @@
|
|||
#define MAX_LZW_BITS 12
|
||||
#define MAX_BITS 4097 /* 2^MAX_LZW_BITS+1 */
|
||||
#define MAX_COLORS 256
|
||||
#define MAX_HOLD_SIZE 256
|
||||
#define MIN_HOLD_SIZE 256
|
||||
|
||||
enum { GIF_TRAILER = 0x3B }; //';'
|
||||
enum { GIF_IMAGE_SEPARATOR = 0x2C }; //','
|
||||
|
@ -28,6 +28,7 @@ typedef enum {
|
|||
gif_global_colormap,
|
||||
gif_image_start,
|
||||
gif_image_header,
|
||||
gif_image_header_continue,
|
||||
gif_image_colormap,
|
||||
gif_image_body,
|
||||
gif_lzw_start,
|
||||
|
@ -95,7 +96,7 @@ typedef struct gif_struct {
|
|||
bool is_transparent; /* TRUE, if tpixel is valid */
|
||||
|
||||
uint16_t prefix[MAX_BITS]; /* LZW decoding tables */
|
||||
uint8_t hold[MAX_HOLD_SIZE]; /* Accumulation buffer */
|
||||
uint8_t* hold; /* Accumulation buffer */
|
||||
uint32_t global_colormap[MAX_COLORS]; /* Default colormap if local not supplied */
|
||||
uint8_t suffix[MAX_BITS]; /* LZW decoding tables */
|
||||
uint8_t stack[MAX_BITS]; /* Base of LZW decoder stack */
|
||||
|
|
|
@ -55,8 +55,6 @@ namespace image {
|
|||
/*
|
||||
* GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
|
||||
*
|
||||
* Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
|
||||
* as each GIF block (except colormaps) can never be bigger than 256 bytes.
|
||||
* Colormaps are directly copied in the resp. global_colormap or the local_colormap of the PAL image frame
|
||||
* So a fixed buffer in gif_struct is good enough.
|
||||
* This buffer is only needed to copy left-over data from one GifWrite call to the next
|
||||
|
@ -96,9 +94,8 @@ nsGIFDecoder2::nsGIFDecoder2(RasterImage &aImage)
|
|||
|
||||
nsGIFDecoder2::~nsGIFDecoder2()
|
||||
{
|
||||
if (mGIFStruct.local_colormap) {
|
||||
moz_free(mGIFStruct.local_colormap);
|
||||
}
|
||||
moz_free(mGIFStruct.local_colormap);
|
||||
moz_free(mGIFStruct.hold);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -164,10 +161,8 @@ void nsGIFDecoder2::BeginGIF()
|
|||
}
|
||||
|
||||
//******************************************************************************
|
||||
nsresult nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
||||
void nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
||||
{
|
||||
uint32_t imageDataLength;
|
||||
nsresult rv;
|
||||
gfxASurface::gfxImageFormat format;
|
||||
if (mGIFStruct.is_transparent)
|
||||
format = gfxASurface::ImageFormatARGB32;
|
||||
|
@ -178,47 +173,17 @@ nsresult nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
|||
// and include transparency to allow for optimization of opaque images
|
||||
if (mGIFStruct.images_decoded) {
|
||||
// Image data is stored with original depth and palette
|
||||
rv = mImage.EnsureFrame(mGIFStruct.images_decoded,
|
||||
mGIFStruct.x_offset, mGIFStruct.y_offset,
|
||||
mGIFStruct.width, mGIFStruct.height,
|
||||
format, aDepth, &mImageData, &imageDataLength,
|
||||
&mColormap, &mColormapSize);
|
||||
|
||||
// While EnsureFrame can reuse frames, we unconditionally increment
|
||||
// mGIFStruct.images_decoded when we're done with a frame, so we both can
|
||||
// and need to zero out the colormap and image data after every call to
|
||||
// EnsureFrame.
|
||||
if (NS_SUCCEEDED(rv) && mColormap) {
|
||||
memset(mColormap, 0, mColormapSize);
|
||||
}
|
||||
NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
|
||||
mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,
|
||||
format, aDepth);
|
||||
} else {
|
||||
// Regardless of depth of input, image is decoded into 24bit RGB
|
||||
rv = mImage.EnsureFrame(mGIFStruct.images_decoded,
|
||||
mGIFStruct.x_offset, mGIFStruct.y_offset,
|
||||
mGIFStruct.width, mGIFStruct.height,
|
||||
format, &mImageData, &imageDataLength);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
memset(mImageData, 0, imageDataLength);
|
||||
|
||||
// Tell the superclass we're starting a frame
|
||||
PostFrameStart();
|
||||
|
||||
if (!mGIFStruct.images_decoded) {
|
||||
// Send a onetime invalidation for the first frame if it has a y-axis offset.
|
||||
// Otherwise, the area may never be refreshed and the placeholder will remain
|
||||
// on the screen. (Bug 37589)
|
||||
if (mGIFStruct.y_offset > 0) {
|
||||
nsIntRect r(0, 0, mGIFStruct.screen_width, mGIFStruct.y_offset);
|
||||
PostInvalidation(r);
|
||||
}
|
||||
NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
|
||||
mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,
|
||||
format);
|
||||
}
|
||||
|
||||
mCurrentFrame = mGIFStruct.images_decoded;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -585,7 +550,13 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
uint8_t* p = (mGIFStruct.state == gif_global_colormap) ? (uint8_t*)mGIFStruct.global_colormap :
|
||||
(mGIFStruct.state == gif_image_colormap) ? (uint8_t*)mColormap :
|
||||
(mGIFStruct.bytes_in_hold) ? mGIFStruct.hold : nullptr;
|
||||
if (p) {
|
||||
|
||||
if (len == 0 && buf == nullptr) {
|
||||
// We've just gotten the frame we asked for. Time to use the data we
|
||||
// stashed away.
|
||||
len = mGIFStruct.bytes_in_hold;
|
||||
q = buf = p;
|
||||
} else if (p) {
|
||||
// Add what we have sofar to the block
|
||||
uint32_t l = std::min(len, mGIFStruct.bytes_to_consume);
|
||||
memcpy(p+mGIFStruct.bytes_in_hold, buf, l);
|
||||
|
@ -596,8 +567,6 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
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;
|
||||
}
|
||||
|
@ -611,7 +580,7 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
// 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) {
|
||||
for (;len >= mGIFStruct.bytes_to_consume; q=buf, mGIFStruct.bytes_in_hold = 0) {
|
||||
// Eat the current block from the buffer, q keeps pointed at current block
|
||||
buf += mGIFStruct.bytes_to_consume;
|
||||
len -= mGIFStruct.bytes_to_consume;
|
||||
|
@ -926,10 +895,40 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
}
|
||||
// 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;
|
||||
BeginImageFrame(realDepth);
|
||||
|
||||
// We now need a new frame from the decoder framework. We leave all our
|
||||
// data in the buffer as if it wasn't consumed, copy to our hold and return
|
||||
// to the decoder framework.
|
||||
uint32_t size = len + mGIFStruct.bytes_to_consume + mGIFStruct.bytes_in_hold;
|
||||
if (size) {
|
||||
if (SetHold(q, mGIFStruct.bytes_to_consume + mGIFStruct.bytes_in_hold, buf, len)) {
|
||||
// Back into the decoder infrastructure so we can get called again.
|
||||
GETN(9, gif_image_header_continue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case gif_image_header_continue:
|
||||
{
|
||||
// While decoders can reuse frames, we unconditionally increment
|
||||
// mGIFStruct.images_decoded when we're done with a frame, so we both can
|
||||
// and need to zero out the colormap and image data after every new frame.
|
||||
memset(mImageData, 0, mImageDataLength);
|
||||
if (mColormap) {
|
||||
memset(mColormap, 0, mColormapSize);
|
||||
}
|
||||
|
||||
if (!mGIFStruct.images_decoded) {
|
||||
// Send a onetime invalidation for the first frame if it has a y-axis offset.
|
||||
// Otherwise, the area may never be refreshed and the placeholder will remain
|
||||
// on the screen. (Bug 37589)
|
||||
if (mGIFStruct.y_offset > 0) {
|
||||
nsIntRect r(0, 0, mGIFStruct.screen_width, mGIFStruct.y_offset);
|
||||
PostInvalidation(r);
|
||||
}
|
||||
}
|
||||
|
||||
if (q[8] & 0x40) {
|
||||
|
@ -948,7 +947,16 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
mGIFStruct.rows_remaining = mGIFStruct.height;
|
||||
mGIFStruct.rowp = mImageData;
|
||||
|
||||
/* bits per pixel is q[8]&0x07 */
|
||||
/* 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 */
|
||||
uint32_t depth = mGIFStruct.global_colormap_depth;
|
||||
if (q[8] & 0x80)
|
||||
depth = (q[8]&0x07) + 1;
|
||||
uint32_t realDepth = depth;
|
||||
while (mGIFStruct.tpixel >= (1 << realDepth) && (realDepth < 8)) {
|
||||
realDepth++;
|
||||
}
|
||||
|
||||
if (q[8] & 0x80) /* has a local colormap? */
|
||||
{
|
||||
|
@ -1027,7 +1035,7 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
break;
|
||||
|
||||
case gif_done:
|
||||
PostDecodeDone();
|
||||
PostDecodeDone(mGIFStruct.loop_count - 1);
|
||||
mGIFOpen = false;
|
||||
goto done;
|
||||
|
||||
|
@ -1046,15 +1054,22 @@ nsGIFDecoder2::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
PostDataError();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Copy the leftover into mGIFStruct.hold
|
||||
mGIFStruct.bytes_in_hold = len;
|
||||
if (len) {
|
||||
// Add what we have sofar to the block
|
||||
uint8_t* p = (mGIFStruct.state == gif_global_colormap) ? (uint8_t*)mGIFStruct.global_colormap :
|
||||
(mGIFStruct.state == gif_image_colormap) ? (uint8_t*)mColormap :
|
||||
mGIFStruct.hold;
|
||||
memcpy(p, buf, len);
|
||||
if (mGIFStruct.state != gif_global_colormap && mGIFStruct.state != gif_image_colormap) {
|
||||
if (!SetHold(buf, len)) {
|
||||
PostDataError();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
uint8_t* p = (mGIFStruct.state == gif_global_colormap) ? (uint8_t*)mGIFStruct.global_colormap :
|
||||
(uint8_t*)mColormap;
|
||||
memcpy(p, buf, len);
|
||||
mGIFStruct.bytes_in_hold = len;
|
||||
}
|
||||
|
||||
mGIFStruct.bytes_to_consume -= len;
|
||||
}
|
||||
|
||||
|
@ -1069,6 +1084,27 @@ done:
|
|||
return;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGIFDecoder2::SetHold(const uint8_t* buf1, uint32_t count1, const uint8_t* buf2 /* = nullptr */, uint32_t count2 /* = 0 */)
|
||||
{
|
||||
// We have to handle the case that buf currently points to hold
|
||||
uint8_t* newHold = (uint8_t *) moz_malloc(std::max(uint32_t(MIN_HOLD_SIZE), count1 + count2));
|
||||
if (!newHold) {
|
||||
mGIFStruct.state = gif_error;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(newHold, buf1, count1);
|
||||
if (buf2) {
|
||||
memcpy(newHold + count1, buf2, count2);
|
||||
}
|
||||
|
||||
moz_free(mGIFStruct.hold);
|
||||
mGIFStruct.hold = newHold;
|
||||
mGIFStruct.bytes_in_hold = count1 + count2;
|
||||
return true;
|
||||
}
|
||||
|
||||
Telemetry::ID
|
||||
nsGIFDecoder2::SpeedHistogram()
|
||||
{
|
||||
|
|
|
@ -35,7 +35,7 @@ private:
|
|||
* frame size information, etc. */
|
||||
|
||||
void BeginGIF();
|
||||
nsresult BeginImageFrame(uint16_t aDepth);
|
||||
void BeginImageFrame(uint16_t aDepth);
|
||||
void EndImageFrame();
|
||||
void FlushImageData();
|
||||
void FlushImageData(uint32_t fromRow, uint32_t rows);
|
||||
|
@ -43,6 +43,8 @@ private:
|
|||
nsresult GifWrite(const uint8_t * buf, uint32_t numbytes);
|
||||
uint32_t OutputRow();
|
||||
bool DoLzw(const uint8_t *q);
|
||||
bool SetHold(const uint8_t* buf, uint32_t count,
|
||||
const uint8_t* buf2 = nullptr, uint32_t count2 = 0);
|
||||
|
||||
inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
|
||||
|
||||
|
|
|
@ -148,21 +148,13 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
|
|||
int32_t width, int32_t height,
|
||||
gfxASurface::gfxImageFormat format)
|
||||
{
|
||||
uint32_t imageDataLength;
|
||||
nsresult rv = mImage.EnsureFrame(GetFrameCount(), x_offset, y_offset,
|
||||
width, height, format,
|
||||
&mImageData, &imageDataLength);
|
||||
if (NS_FAILED(rv))
|
||||
longjmp(png_jmpbuf(mPNG), 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
NeedNewFrame(GetFrameCount(), x_offset, y_offset, width, height, format);
|
||||
|
||||
mFrameRect.x = x_offset;
|
||||
mFrameRect.y = y_offset;
|
||||
mFrameRect.width = width;
|
||||
mFrameRect.height = height;
|
||||
|
||||
// Tell the superclass we're starting a frame
|
||||
PostFrameStart();
|
||||
|
||||
PR_LOG(GetPNGDecoderAccountingLog(), PR_LOG_DEBUG,
|
||||
("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
|
||||
"image frame with %dx%d pixels in container %p",
|
||||
|
@ -292,10 +284,6 @@ nsPNGDecoder::InitInternal()
|
|||
void
|
||||
nsPNGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
|
||||
{
|
||||
// We use gotos, so we need to declare variables here
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
|
||||
NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
|
||||
|
||||
// If we only want width/height, we don't need to go through libpng
|
||||
|
@ -322,8 +310,8 @@ nsPNGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount)
|
|||
}
|
||||
|
||||
// Grab the width and height, accounting for endianness (thanks libpng!)
|
||||
width = png_get_uint_32(mHeaderBuf + WIDTH_OFFSET);
|
||||
height = png_get_uint_32(mHeaderBuf + HEIGHT_OFFSET);
|
||||
uint32_t width = png_get_uint_32(mHeaderBuf + WIDTH_OFFSET);
|
||||
uint32_t height = png_get_uint_32(mHeaderBuf + HEIGHT_OFFSET);
|
||||
|
||||
// Too big?
|
||||
if ((width > MOZ_PNG_MAX_DIMENSION) || (height > MOZ_PNG_MAX_DIMENSION)) {
|
||||
|
@ -668,7 +656,12 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
*/
|
||||
png_set_crc_action(png_ptr, PNG_CRC_NO_CHANGE, PNG_CRC_ERROR_QUIT);
|
||||
|
||||
return;
|
||||
if (!decoder->mFrameIsHidden) {
|
||||
/* We know that we need a new frame, so pause input so the decoder
|
||||
* infrastructure can give it to us.
|
||||
*/
|
||||
png_process_data_pause(png_ptr, /* save = */ 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -829,6 +822,11 @@ nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
|
|||
height = png_get_next_frame_height(png_ptr, decoder->mInfo);
|
||||
|
||||
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
|
||||
|
||||
/* We know that we need a new frame, so pause input so the decoder
|
||||
* infrastructure can give it to us.
|
||||
*/
|
||||
png_process_data_pause(png_ptr, /* save = */ 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,8 @@ public:
|
|||
if (png_get_IHDR(mPNG, mInfo, &png_width, &png_height, &png_bit_depth,
|
||||
&png_color_type, NULL, NULL, NULL)) {
|
||||
|
||||
return (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
|
||||
return ((png_color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
|
||||
png_color_type == PNG_COLOR_TYPE_RGB) &&
|
||||
png_bit_depth == 8);
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -22,6 +22,7 @@ Decoder::Decoder(RasterImage &aImage)
|
|||
, mDataError(false)
|
||||
, mFrameCount(0)
|
||||
, mFailCode(NS_OK)
|
||||
, mNeedsNewFrame(false)
|
||||
, mInitialized(false)
|
||||
, mSizeDecode(false)
|
||||
, mInFrame(false)
|
||||
|
@ -82,6 +83,40 @@ Decoder::Write(const char* aBuffer, uint32_t aCount)
|
|||
|
||||
// Pass the data along to the implementation
|
||||
WriteInternal(aBuffer, aCount);
|
||||
|
||||
// If the decoder told us that it needs a new frame to proceed, let's create
|
||||
// one and call it again.
|
||||
while (mNeedsNewFrame && !HasDataError()) {
|
||||
nsresult rv;
|
||||
if (mNewFrameData.mPaletteDepth) {
|
||||
rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX,
|
||||
mNewFrameData.mOffsetY, mNewFrameData.mWidth,
|
||||
mNewFrameData.mHeight, mNewFrameData.mFormat,
|
||||
mNewFrameData.mPaletteDepth,
|
||||
&mImageData, &mImageDataLength,
|
||||
&mColormap, &mColormapSize);
|
||||
} else {
|
||||
rv = mImage.EnsureFrame(mNewFrameData.mFrameNum, mNewFrameData.mOffsetX,
|
||||
mNewFrameData.mOffsetY, mNewFrameData.mWidth,
|
||||
mNewFrameData.mHeight, mNewFrameData.mFormat,
|
||||
&mImageData, &mImageDataLength);
|
||||
}
|
||||
|
||||
// Release our new frame data before talking to anyone else so they can
|
||||
// tell us if they need yet another.
|
||||
mNeedsNewFrame = false;
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// We've now created our frame, so be sure we keep track of it correctly.
|
||||
PostFrameStart();
|
||||
|
||||
// Tell the decoder to use the data it saved when it asked for a new frame.
|
||||
WriteInternal(nullptr, 0);
|
||||
} else {
|
||||
PostDataError();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -317,5 +352,21 @@ Decoder::PostDecoderError(nsresult aFailureCode)
|
|||
NS_WARNING("Image decoding error - This is probably a bug!");
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::NeedNewFrame(uint32_t framenum, uint32_t x_offset, uint32_t y_offset,
|
||||
uint32_t width, uint32_t height,
|
||||
gfxASurface::gfxImageFormat format,
|
||||
uint8_t palette_depth /* = 0 */)
|
||||
{
|
||||
// Decoders should never call NeedNewFrame without yielding back to Write().
|
||||
MOZ_ASSERT(!mNeedsNewFrame);
|
||||
|
||||
// We don't want images going back in time or skipping frames.
|
||||
MOZ_ASSERT(framenum == mFrameCount || framenum == (mFrameCount + 1));
|
||||
|
||||
mNewFrameData = NewFrameData(framenum, x_offset, y_offset, width, height, format, palette_depth);
|
||||
mNeedsNewFrame = true;
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -184,6 +184,15 @@ protected:
|
|||
void PostDataError();
|
||||
void PostDecoderError(nsresult aFailCode);
|
||||
|
||||
// This is called by decoders when they need a new frame. These decoders
|
||||
// must then save the data they have been sent but not yet processed and
|
||||
// return from WriteInternal. When the new frame is created, WriteInternal
|
||||
// will be called again with nullptr and 0 as arguments.
|
||||
void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset,
|
||||
uint32_t width, uint32_t height,
|
||||
gfxASurface::gfxImageFormat format,
|
||||
uint8_t palette_depth = 0);
|
||||
|
||||
/*
|
||||
* Member variables.
|
||||
*
|
||||
|
@ -208,6 +217,32 @@ private:
|
|||
|
||||
nsresult mFailCode;
|
||||
|
||||
struct NewFrameData
|
||||
{
|
||||
NewFrameData()
|
||||
{}
|
||||
|
||||
NewFrameData(uint32_t num, uint32_t offsetx, uint32_t offsety,
|
||||
uint32_t width, uint32_t height,
|
||||
gfxASurface::gfxImageFormat format, uint8_t paletteDepth)
|
||||
: mFrameNum(num)
|
||||
, mOffsetX(offsetx)
|
||||
, mOffsetY(offsety)
|
||||
, mWidth(width)
|
||||
, mHeight(height)
|
||||
, mFormat(format)
|
||||
, mPaletteDepth(paletteDepth)
|
||||
{}
|
||||
uint32_t mFrameNum;
|
||||
uint32_t mOffsetX;
|
||||
uint32_t mOffsetY;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
gfxASurface::gfxImageFormat mFormat;
|
||||
uint8_t mPaletteDepth;
|
||||
};
|
||||
NewFrameData mNewFrameData;
|
||||
bool mNeedsNewFrame;
|
||||
bool mInitialized;
|
||||
bool mSizeDecode;
|
||||
bool mInFrame;
|
||||
|
|
|
@ -210,6 +210,7 @@ MOZ_PNG_get_tRNS
|
|||
MOZ_PNG_get_valid
|
||||
MOZ_PNG_longjmp
|
||||
MOZ_PNG_process_data
|
||||
MOZ_PNG_process_data_pause
|
||||
MOZ_PNG_progressive_combine_row
|
||||
MOZ_PNG_read_update_info
|
||||
MOZ_PNG_set_cHRM
|
||||
|
|
Загрузка…
Ссылка в новой задаче