icecat: add release icecat-140.10.1-1gnu1 for ecne

This commit is contained in:
Ark74 2026-05-04 16:58:41 -06:00
parent a5f93cb214
commit ff85d7c623
1256 changed files with 63469 additions and 24141 deletions

View file

@ -240,7 +240,8 @@ ImageWrapper::RequestDiscard() { return mInnerImage->RequestDiscard(); }
NS_IMETHODIMP_(void)
ImageWrapper::RequestRefresh(const TimeStamp& aTime) {
return mInnerImage->RequestRefresh(aTime);
RefPtr<Image> inner = mInnerImage;
return inner->RequestRefresh(aTime);
}
NS_IMETHODIMP

View file

@ -81,6 +81,8 @@ RasterImage::RasterImage(nsIURI* aURI /* = nullptr */)
//******************************************************************************
RasterImage::~RasterImage() {
mIsBeingDestroyed = true;
// Make sure our SourceBuffer is marked as complete. This will ensure that any
// outstanding decoders terminate.
if (!mSourceBuffer->IsComplete()) {
@ -489,8 +491,12 @@ RasterImage::WillDrawOpaqueNow() {
void RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) {
MOZ_ASSERT(mProgressTracker);
if (mIsBeingDestroyed) {
return;
}
bool animatedFramesDiscarded =
mAnimationState && aSurfaceKey.Playback() == PlaybackType::eAnimated;
aSurfaceKey.Playback() == PlaybackType::eAnimated;
nsCOMPtr<nsIEventTarget> eventTarget = do_GetMainThread();

View file

@ -17,6 +17,7 @@
#ifndef mozilla_image_RasterImage_h
#define mozilla_image_RasterImage_h
#include "mozilla/Atomics.h"
#include "Image.h"
#include "nsCOMPtr.h"
#include "imgIContainer.h"
@ -382,6 +383,8 @@ class RasterImage final : public ImageResource,
// This is currently only used for statistics
int32_t mDecodeCount;
Atomic<bool> mIsBeingDestroyed{false};
#ifdef DEBUG
uint32_t mFramesNotified;
#endif

View file

@ -1603,6 +1603,10 @@ void VectorImage::OnSVGDocumentError() {
// invalid document.
ReportDocumentUseCounters();
// ProgressTracker::SyncNotifyProgress may release us, so ensure we
// stick around long enough to complete our work.
RefPtr<VectorImage> kungFuDeathGrip(this);
if (mProgressTracker) {
// Notify observers about the error and unblock page load.
Progress progress = FLAG_HAS_ERROR;

View file

@ -238,7 +238,8 @@ nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
nsBMPDecoder::~nsBMPDecoder() {}
// Obtains the size of the compressed image resource.
int32_t nsBMPDecoder::GetCompressedImageSize() const {
uint32_t nsBMPDecoder::GetCompressedImageSize() const {
// Keep this in sync with the overflow check in ReadInfoHeaderRest.
// In the RGB case mImageSize might not be set, so compute it manually.
MOZ_ASSERT(mPixelRowSize != 0);
return mH.mCompression == Compression::RGB ? mPixelRowSize * AbsoluteHeight()
@ -637,6 +638,16 @@ LexerTransition<nsBMPDecoder::State> nsBMPDecoder::ReadInfoHeaderRest(
mPixelRowSize += 4 - surplus;
}
if (mIsWithinICO && mH.mCompression == Compression::RGB) {
// The ICO decoders calls GetCompressedImageSize so we need to make sure the
// computation it does cannot overflow. Keep this in sync with that
// function.
auto product = CheckedInt<uint32_t>(mPixelRowSize) * AbsoluteHeight();
if (!product.isValid()) {
return Transition::TerminateFailure();
}
}
size_t bitFieldsLengthStillToRead = 0;
if (mH.mCompression == Compression::BITFIELDS) {
// Need to read bitfields.

View file

@ -159,7 +159,7 @@ class nsBMPDecoder : public Decoder {
size_t GetImageDataLength() const { return mImageDataLength; }
/// Obtains the size of the compressed image resource.
int32_t GetCompressedImageSize() const;
uint32_t GetCompressedImageSize() const;
/// Mark this BMP as being within an ICO file. Only used for testing purposes
/// because the ICO-specific constructor does this marking automatically.
@ -205,7 +205,7 @@ class nsBMPDecoder : public Decoder {
nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength,
bool aForClipboard);
int32_t AbsoluteHeight() const { return abs(mH.mHeight); }
uint32_t AbsoluteHeight() const { return abs(mH.mHeight); }
uint32_t* RowBuffer();
void ClearRowBufferRemainder();

View file

@ -136,7 +136,7 @@ size_t nsICODecoder::FirstResourceOffset() const {
// The first resource starts right after the directory, which starts right
// after the ICO header.
return ICOHEADERSIZE + mNumIcons * ICODIRENTRYSIZE;
return ICOHEADERSIZE + static_cast<size_t>(mNumIcons) * ICODIRENTRYSIZE;
}
LexerTransition<ICOState> nsICODecoder::ReadDirEntry(const char* aData) {
@ -221,7 +221,11 @@ LexerTransition<ICOState> nsICODecoder::IterateUnsizedDirEntry() {
// Move to the resource data to start metadata decoding.
mDirEntry = &mUnsizedDirEntries[0];
size_t offsetToResource = mDirEntry->mImageOffset - FirstResourceOffset();
// We ignored any dir entries whose offset didn't make sense before this.
MOZ_ASSERT(static_cast<size_t>(mDirEntry->mImageOffset) >=
FirstResourceOffset());
size_t offsetToResource =
static_cast<size_t>(mDirEntry->mImageOffset) - FirstResourceOffset();
return Transition::ToUnbuffered(ICOState::FOUND_RESOURCE,
ICOState::SKIP_TO_RESOURCE, offsetToResource);
}
@ -316,6 +320,9 @@ LexerTransition<ICOState> nsICODecoder::FinishDirEntry() {
mDownscaler.emplace(OutputSize().ToUnknownSize());
}
// We ignored any dir entries whose offset didn't make sense before this.
MOZ_ASSERT(static_cast<size_t>(mDirEntry->mImageOffset) >=
FirstResourceOffset());
size_t offsetToResource = mDirEntry->mImageOffset - FirstResourceOffset();
return Transition::ToUnbuffered(ICOState::FOUND_RESOURCE,
ICOState::SKIP_TO_RESOURCE, offsetToResource);
@ -437,37 +444,67 @@ LexerTransition<ICOState> nsICODecoder::ReadBIH(const char* aData) {
// Do we have an AND mask on this BMP? If so, we need to read it after we read
// the BMP data itself.
uint32_t bmpDataLength = bmpDecoder->GetCompressedImageSize() + 4 * numColors;
bool hasANDMask = (BITMAPINFOSIZE + bmpDataLength) < mDirEntry->mBytesInRes;
auto bmpDataLength =
CheckedInt<uint32_t>(bmpDecoder->GetCompressedImageSize()) +
4 * numColors;
auto fullBmpLength = bmpDataLength + BITMAPINFOSIZE;
if (!bmpDataLength.isValid() || !fullBmpLength.isValid() ||
fullBmpLength.value() > mDirEntry->mBytesInRes) {
// Claimed data length inside the bmp resource exceeds dir entry size.
return Transition::TerminateFailure();
}
bool hasANDMask = fullBmpLength.value() < mDirEntry->mBytesInRes;
ICOState afterBMPState =
hasANDMask ? ICOState::PREPARE_FOR_MASK : ICOState::FINISHED_RESOURCE;
// Read in the rest of the BMP unbuffered.
return Transition::ToUnbuffered(afterBMPState, ICOState::READ_RESOURCE,
bmpDataLength);
bmpDataLength.value());
}
LexerTransition<ICOState> nsICODecoder::PrepareForMask() {
MOZ_ASSERT(mDirEntry);
MOZ_ASSERT(mContainedDecoder->GetDecodeDone());
// We have received all of the data required by the BMP decoder so flushing
// here guarantees the decode has finished.
// here guarantees the decode has finished, if we have a valid file.
if (!FlushContainedDecoder()) {
return Transition::TerminateFailure();
}
MOZ_ASSERT(mContainedDecoder->GetDecodeDone());
if (!mContainedDecoder->GetDecodeDone()) {
return Transition::TerminateFailure();
}
RefPtr<nsBMPDecoder> bmpDecoder =
static_cast<nsBMPDecoder*>(mContainedDecoder.get());
if (!bmpDecoder->GetImageData() || bmpDecoder->GetImageDataLength() == 0) {
return Transition::TerminateFailure();
}
if (mDownscaler) {
if (mDownscaler->TargetSize().width < 0 ||
mDownscaler->TargetSize().height < 0 ||
bmpDecoder->GetImageDataLength() !=
static_cast<size_t>(mDownscaler->TargetSize().width *
mDownscaler->TargetSize().height * 4)) {
return Transition::TerminateFailure();
}
} else {
if (mDirEntry->mSize.width < 0 || mDirEntry->mSize.height < 0 ||
bmpDecoder->GetImageDataLength() !=
static_cast<size_t>(mDirEntry->mSize.width *
mDirEntry->mSize.height * 4)) {
return Transition::TerminateFailure();
}
}
uint16_t numColors = GetNumColors();
MOZ_ASSERT(numColors != uint16_t(-1));
// Determine the length of the AND mask.
uint32_t bmpLengthWithHeader =
BITMAPINFOSIZE + bmpDecoder->GetCompressedImageSize() + 4 * numColors;
// We can't get here unless this is true.
MOZ_ASSERT(bmpLengthWithHeader < mDirEntry->mBytesInRes);
uint32_t maskLength = mDirEntry->mBytesInRes - bmpLengthWithHeader;
@ -491,9 +528,6 @@ LexerTransition<ICOState> nsICODecoder::PrepareForMask() {
// produced, so we need to downscale the mask into a temporary buffer and then
// combine the mask's alpha values with the color values from the image.
if (mDownscaler) {
MOZ_ASSERT(bmpDecoder->GetImageDataLength() ==
mDownscaler->TargetSize().width *
mDownscaler->TargetSize().height * sizeof(uint32_t));
mMaskBuffer =
MakeUniqueFallible<uint8_t[]>(bmpDecoder->GetImageDataLength());
if (NS_WARN_IF(!mMaskBuffer)) {
@ -616,7 +650,11 @@ LexerTransition<ICOState> nsICODecoder::FinishResource() {
return Transition::TerminateFailure();
}
MOZ_ASSERT(mContainedDecoder->GetDecodeDone());
if (!mContainedDecoder->GetDecodeDone()) {
// We've sent as much data as the dir entry says for this resource, if it's
// not done by now then something is corrupt.
return Transition::TerminateFailure();
}
// If it is a metadata decode, all we were trying to get was the size
// information missing from the dir entry.

View file

@ -448,9 +448,6 @@ uint32_t nsPNGDecoder::ReadColorProfile(png_structp png_ptr, png_infop info_ptr,
mInProfile = qcms_profile_create_cicp(
primaries, ChooseTransferCharacteristics(tc));
if (mInProfile) {
if (!(color_type & PNG_COLOR_MASK_COLOR)) {
png_set_gray_to_rgb(png_ptr);
}
return qcms_profile_get_rendering_intent(mInProfile);
}
}
@ -477,9 +474,7 @@ uint32_t nsPNGDecoder::ReadColorProfile(png_structp png_ptr, png_infop info_ptr,
mismatch = true;
}
} else {
if (profileSpace == icSigRgbData) {
png_set_gray_to_rgb(png_ptr);
} else if (profileSpace != icSigGrayData) {
if (profileSpace != icSigRgbData && profileSpace != icSigGrayData) {
mismatch = true;
}
}
@ -498,7 +493,6 @@ uint32_t nsPNGDecoder::ReadColorProfile(png_structp png_ptr, png_infop info_ptr,
*sRGBTag = true;
int fileIntent;
png_set_gray_to_rgb(png_ptr);
png_get_sRGB(png_ptr, info_ptr, &fileIntent);
uint32_t map[] = {QCMS_INTENT_PERCEPTUAL, QCMS_INTENT_RELATIVE_COLORIMETRIC,
QCMS_INTENT_SATURATION,
@ -523,10 +517,6 @@ uint32_t nsPNGDecoder::ReadColorProfile(png_structp png_ptr, png_infop info_ptr,
mInProfile = qcms_profile_create_rgb_with_gamma(whitePoint, primaries,
1.0 / gammaOfFile);
if (mInProfile) {
png_set_gray_to_rgb(png_ptr);
}
}
return QCMS_INTENT_PERCEPTUAL; // Our default
@ -593,9 +583,9 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
// We only need to extract the color profile for non-metadata decodes. It is
// fairly expensive to read the profile and create the transform so we should
// avoid it if not necessary.
uint32_t intent = -1;
bool sRGBTag = false;
if (!decoder->IsMetadataDecode()) {
uint32_t intent = -1;
bool sRGBTag = false;
if (decoder->mCMSMode != CMSMode::Off) {
intent = gfxPlatform::GetRenderingIntent();
uint32_t pIntent =
@ -604,16 +594,75 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
if (intent == uint32_t(-1)) {
intent = pIntent;
}
}
const bool hasColorInfo = decoder->mInProfile || sRGBTag;
if (!hasColorInfo || !decoder->GetCMSOutputProfile()) {
png_set_gray_to_rgb(png_ptr);
// only do gamma correction if CMS isn't entirely disabled
if (decoder->mCMSMode != CMSMode::Off) {
PNGDoGammaCorrection(png_ptr, info_ptr);
// png_get_channels won't return accurate info for determining the alpha
// status until after we call png_read_update_info below so we use this
// method of determining if we will have alpha so that we can select the
// correct qcms input type here.
const bool willHaveAlpha =
(color_type & PNG_COLOR_MASK_ALPHA) || num_trans != 0;
// Determine the qcms transform here, before png_read_update_info commits
// libpng to a specific output format. For gray images the presence or
// absence of a qcms transform determines if we want libpng to output
// gray data (we call qcms to transform it to rgb before passing it to
// the surface pipe), or rgb data (no qcms transform so we need rgb data
// to pass directly into the surface pipe).
if (decoder->mInProfile && decoder->GetCMSOutputProfile()) {
uint32_t profileSpace =
qcms_profile_get_color_space(decoder->mInProfile);
decoder->mUsePipeTransform = profileSpace != icSigGrayData;
qcms_data_type inType, outType;
if (decoder->mUsePipeTransform) {
// libpng outputs data in RGBA order and we want our final output to
// be BGRA order. SurfacePipe takes care of this for us but
// unfortunately the swizzle to change the order can happen before or
// after color management depending on if we have alpha. If we have
// alpha then the order will be color management then swizzle. If we
// do not have alpha then the order will be swizzle then color
// management. See CreateSurfacePipe
// https://searchfox.org/mozilla-central/rev/7d6651d29c5c1620bc059f879a3e9bbfb53f271f/image/SurfacePipeFactory.h#133-145
if (willHaveAlpha) {
inType = QCMS_DATA_RGBA_8;
outType = QCMS_DATA_RGBA_8;
} else {
inType = gfxPlatform::GetCMSOSRGBAType();
outType = inType;
}
} else {
// qcms operates on the data before we hand it to SurfacePipe.
inType = willHaveAlpha ? QCMS_DATA_GRAYA_8 : QCMS_DATA_GRAY_8;
outType = gfxPlatform::GetCMSOSRGBAType();
}
decoder->mTransform = qcms_transform_create(
decoder->mInProfile, inType, decoder->GetCMSOutputProfile(),
outType, (qcms_intent)intent);
} else if ((sRGBTag && decoder->mCMSMode == CMSMode::TaggedOnly) ||
decoder->mCMSMode == CMSMode::All) {
// See comment above about SurfacePipe, color management and ordering.
decoder->mUsePipeTransform = true;
if (willHaveAlpha) {
decoder->mTransform =
decoder->GetCMSsRGBTransform(SurfaceFormat::R8G8B8A8);
} else {
decoder->mTransform =
decoder->GetCMSsRGBTransform(SurfaceFormat::OS_RGBA);
}
}
}
// Expand gray to RGB unless we will pass the data to qcms to handle it via
// a non-pipe transform.
if (!decoder->mTransform || decoder->mUsePipeTransform) {
png_set_gray_to_rgb(png_ptr);
}
// Only apply libpng gamma correction when there is no qcms transform to
// handle it, and CMS is not entirely disabled.
if (!decoder->mTransform && decoder->mCMSMode != CMSMode::Off) {
PNGDoGammaCorrection(png_ptr, info_ptr);
}
}
// Let libpng expand interlaced images.
@ -651,7 +700,6 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
}
#endif
auto transparency = decoder->GetTransparencyType(frameRect);
if (decoder->IsMetadataDecode()) {
// If we are animated then the first frame rect is either:
// 1) the whole image if the IDAT chunk is part of the animation
@ -660,61 +708,14 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
// PostHasTransparency in the metadata decode if we need to. So it's
// okay to pass IntRect(0, 0, width, height) here for animated images;
// they will call with the proper first frame rect in the full decode.
decoder->PostHasTransparencyIfNeeded(transparency);
decoder->PostHasTransparencyIfNeeded(
decoder->GetTransparencyType(frameRect));
// We have the metadata we're looking for, so stop here, before we allocate
// buffers below.
return decoder->DoTerminate(png_ptr, TerminalState::SUCCESS);
}
if (decoder->mInProfile && decoder->GetCMSOutputProfile()) {
qcms_data_type inType;
qcms_data_type outType;
uint32_t profileSpace = qcms_profile_get_color_space(decoder->mInProfile);
decoder->mUsePipeTransform = profileSpace != icSigGrayData;
if (decoder->mUsePipeTransform) {
// libpng outputs data in RGBA order and we want our final output to be
// BGRA order. SurfacePipe takes care of this for us but unfortunately the
// swizzle to change the order can happen before or after color management
// depending on if we have alpha. If we have alpha then the order will be
// color management then swizzle. If we do not have alpha then the order
// will be swizzle then color management. See CreateSurfacePipe
// https://searchfox.org/mozilla-central/rev/7d6651d29c5c1620bc059f879a3e9bbfb53f271f/image/SurfacePipeFactory.h#133-145
if (transparency == TransparencyType::eAlpha) {
inType = QCMS_DATA_RGBA_8;
outType = QCMS_DATA_RGBA_8;
} else {
inType = gfxPlatform::GetCMSOSRGBAType();
outType = inType;
}
} else {
// qcms operates on the data before we hand it to SurfacePipe.
if (color_type & PNG_COLOR_MASK_ALPHA) {
inType = QCMS_DATA_GRAYA_8;
outType = gfxPlatform::GetCMSOSRGBAType();
} else {
inType = QCMS_DATA_GRAY_8;
outType = gfxPlatform::GetCMSOSRGBAType();
}
}
decoder->mTransform = qcms_transform_create(decoder->mInProfile, inType,
decoder->GetCMSOutputProfile(),
outType, (qcms_intent)intent);
} else if ((sRGBTag && decoder->mCMSMode == CMSMode::TaggedOnly) ||
decoder->mCMSMode == CMSMode::All) {
// See comment above about SurfacePipe, color management and ordering.
decoder->mUsePipeTransform = true;
if (transparency == TransparencyType::eAlpha) {
decoder->mTransform =
decoder->GetCMSsRGBTransform(SurfaceFormat::R8G8B8A8);
} else {
decoder->mTransform =
decoder->GetCMSsRGBTransform(SurfaceFormat::OS_RGBA);
}
}
#ifdef PNG_APNG_SUPPORTED
if (isAnimated) {
png_set_progressive_frame_fn(png_ptr, nsPNGDecoder::frame_info_callback,