diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index bc3031d2f118..19b7bbc7c4ed 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -546,7 +546,6 @@ private: DECL_GFX_PREF(Live, "image.animated.generate-full-frames", ImageAnimatedGenerateFullFrames, bool, false); DECL_GFX_PREF(Live, "image.animated.resume-from-last-displayed", ImageAnimatedResumeFromLastDisplayed, bool, false); DECL_GFX_PREF(Live, "image.cache.factor2.threshold-surfaces", ImageCacheFactor2ThresholdSurfaces, int32_t, -1); - DECL_GFX_PREF(Live, "image.cache.max-rasterized-svg-threshold-kb", ImageCacheMaxRasterizedSVGThresholdKB, int32_t, 90*1024); DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024); DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500); DECL_GFX_PREF(Live, "image.decode-immediately.enabled", ImageDecodeImmediatelyEnabled, bool, false); diff --git a/image/Image.cpp b/image/Image.cpp index fa6b9c0657bc..650c9da83916 100644 --- a/image/Image.cpp +++ b/image/Image.cpp @@ -160,7 +160,6 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager, case ImgDrawResult::SUCCESS: case ImgDrawResult::BAD_IMAGE: case ImgDrawResult::BAD_ARGS: - case ImgDrawResult::NOT_SUPPORTED: container.forget(aOutContainer); return entry->mLastDrawResult; case ImgDrawResult::NOT_READY: @@ -219,7 +218,6 @@ ImageResource::GetImageContainerImpl(LayerManager* aManager, case ImgDrawResult::SUCCESS: case ImgDrawResult::BAD_IMAGE: case ImgDrawResult::BAD_ARGS: - case ImgDrawResult::NOT_SUPPORTED: container.forget(aOutContainer); return entry->mLastDrawResult; case ImgDrawResult::NOT_READY: diff --git a/image/Image.h b/image/Image.h index d72bd67cd99a..ab405e6228a5 100644 --- a/image/Image.h +++ b/image/Image.h @@ -337,24 +337,6 @@ protected: bool mAnimating:1; // Are we currently animating? bool mError:1; // Error handling - /** - * Attempt to find a matching cached surface in the SurfaceCache, and if not - * available, request the production of such a surface (either synchronously - * or asynchronously). - * - * If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be - * the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the - * size is a hint as to what we expect the surface size to be, once the best - * fitting size is available. It may or may not match the size of the surface - * returned at this moment. This is useful for choosing how to store the final - * result (e.g. if going into an ImageContainer, ideally we would share the - * same container for many requested sizes, if they all end up with the same - * best fit size in the end). - * - * A valid surface should only be returned for SUCCESS and INCOMPLETE. - * - * Any other draw result is invalid. - */ virtual Tuple> GetFrameInternal(const gfx::IntSize& aSize, const Maybe& aSVGContext, diff --git a/image/LookupResult.h b/image/LookupResult.h index 264c576e8757..b49615d00748 100644 --- a/image/LookupResult.h +++ b/image/LookupResult.h @@ -109,11 +109,8 @@ private: DrawableSurface mSurface; MatchType mMatchType; - /// mSuggestedSize will be the size of the returned surface if the result is - /// SUBSTITUTE_BECAUSE_BEST. It will be empty for EXACT, and can contain a - /// non-empty size possibly different from the returned surface (if any) for - /// all other results. If non-empty, it will always be the size the caller - /// should request any decodes at. + /// If given, the size the caller should request a decode at. This may or may + /// not match the size the caller requested from the cache. gfx::IntSize mSuggestedSize; }; diff --git a/image/SVGDrawingParameters.h b/image/SVGDrawingParameters.h index 0d243b3b1711..322151a68367 100644 --- a/image/SVGDrawingParameters.h +++ b/image/SVGDrawingParameters.h @@ -24,8 +24,7 @@ struct SVGDrawingParameters typedef mozilla::gfx::SamplingFilter SamplingFilter; SVGDrawingParameters(gfxContext* aContext, - const nsIntSize& aRasterSize, - const nsIntSize& aDrawSize, + const nsIntSize& aSize, const ImageRegion& aRegion, SamplingFilter aSamplingFilter, const Maybe& aSVGContext, @@ -33,12 +32,11 @@ struct SVGDrawingParameters uint32_t aFlags, float aOpacity) : context(aContext) - , size(aRasterSize) - , drawSize(aDrawSize) + , size(aSize.width, aSize.height) , region(aRegion) , samplingFilter(aSamplingFilter) , svgContext(aSVGContext) - , viewportSize(aRasterSize) + , viewportSize(aSize) , animationTime(aAnimationTime) , flags(aFlags) , opacity(aOpacity) @@ -52,8 +50,7 @@ struct SVGDrawingParameters } gfxContext* context; - IntSize size; // Size to rasterize a surface at. - IntSize drawSize; // Size to draw the given surface at. + IntSize size; ImageRegion region; SamplingFilter samplingFilter; const Maybe& svgContext; diff --git a/image/SurfaceCache.cpp b/image/SurfaceCache.cpp index 9e49b22716b4..7d921cc32e0b 100644 --- a/image/SurfaceCache.cpp +++ b/image/SurfaceCache.cpp @@ -12,7 +12,6 @@ #include #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" -#include "mozilla/CheckedInt.h" #include "mozilla/DebugOnly.h" #include "mozilla/Likely.h" #include "mozilla/Move.h" @@ -252,11 +251,10 @@ class ImageSurfaceCache { ~ImageSurfaceCache() { } public: - explicit ImageSurfaceCache(const ImageKey aImageKey) + ImageSurfaceCache() : mLocked(false) , mFactor2Mode(false) , mFactor2Pruned(false) - , mIsVectorImage(aImageKey->GetType() == imgIContainer::TYPE_VECTOR) { } MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageSurfaceCache) @@ -332,7 +330,7 @@ public: // Try for a best match second, if using compact. IntSize suggestedSize = SuggestedSize(aIdealKey.Size()); - if (suggestedSize != aIdealKey.Size()) { + if (mFactor2Mode) { if (!exactMatch) { SurfaceKey compactKey = aIdealKey.CloneWithSize(suggestedSize); mSurfaces.Get(compactKey, getter_AddRefs(exactMatch)); @@ -403,7 +401,7 @@ public: } else if (aIdealKey.Size() != bestMatch->GetSurfaceKey().Size()) { // The best factor of 2 match is still decoding, but the best we've got. MOZ_ASSERT(suggestedSize != aIdealKey.Size()); - MOZ_ASSERT(mFactor2Mode || mIsVectorImage); + MOZ_ASSERT(mFactor2Mode); matchType = MatchType::SUBSTITUTE_BECAUSE_BEST; } else { // The exact match is still decoding, but it's the best we've got. @@ -435,18 +433,20 @@ public: return; } - // Determine how many native surfaces this image has. If it is zero, and it - // is a vector image, then we should impute a single native size. Otherwise, - // it may be zero because we don't know yet, or the image has an error, or - // it isn't supported. + // Determine how many native surfaces this image has. Zero means we either + // don't know yet (in which case do nothing), or we don't want to limit the + // number of surfaces for this image. + // + // XXX(aosmond): Vector images have zero native sizes. This is because they + // are regenerated at the given size. There isn't an equivalent concept to + // the native size (and w/h ratio) to provide a frame of reference to what + // are "good" sizes. While it is desirable to have a similar mechanism as + // that for raster images, it will need a different approach. auto first = ConstIter(); NotNull current = WrapNotNull(first.UserData()); Image* image = static_cast(current->GetImageKey()); size_t nativeSizes = image->GetNativeSizesLength(); - if (mIsVectorImage) { - MOZ_ASSERT(nativeSizes == 0); - nativeSizes = 1; - } else if (nativeSizes == 0) { + if (nativeSizes == 0) { return; } @@ -530,33 +530,6 @@ public: } IntSize SuggestedSize(const IntSize& aSize) const - { - IntSize suggestedSize = SuggestedSizeInternal(aSize); - MOZ_ASSERT(SurfaceCache::IsLegalSize(suggestedSize)); - - // Whether or not we are in factor of 2 mode, vector image rasterization is - // clamped at a configured maximum if the caller is willing to accept - // substitutes. - if (mIsVectorImage) { - // If we exceed the maximum, we need to scale the size downwards to fit. - // It shouldn't get here if it is significantly larger because - // VectorImage::UseSurfaceCacheForSize should prevent us from requesting - // a rasterized version of a surface greater than 4x the maximum. - int32_t maxSizeKB = gfxPrefs::ImageCacheMaxRasterizedSVGThresholdKB(); - int32_t proposedKB = suggestedSize.width * suggestedSize.height / 256; - if (maxSizeKB >= proposedKB) { - return suggestedSize; - } - - double scale = sqrt(double(maxSizeKB) / proposedKB); - suggestedSize.width = int32_t(scale * suggestedSize.width); - suggestedSize.height = int32_t(scale * suggestedSize.height); - } - - return suggestedSize; - } - - IntSize SuggestedSizeInternal(const IntSize& aSize) const { // When not in factor of 2 mode, we can always decode at the given size. if (!mFactor2Mode) { @@ -579,48 +552,11 @@ public: NS_FAILED(image->GetHeight(&factorSize.height)) || factorSize.IsEmpty()) { // We should not have entered factor of 2 mode without a valid size, and - // several successfully decoded surfaces. Note that valid vector images - // may have a default size of 0x0, and those are not yet supported. + // several successfully decoded surfaces. MOZ_ASSERT_UNREACHABLE("Expected valid native size!"); return aSize; } - if (mIsVectorImage) { - // Ensure the aspect ratio matches the native size before forcing the - // caller to accept a factor of 2 size. The difference between the aspect - // ratios is: - // - // delta = nativeWidth/nativeHeight - desiredWidth/desiredHeight - // - // delta*nativeHeight*desiredHeight = nativeWidth*desiredHeight - // - desiredWidth*nativeHeight - // - // Using the maximum accepted delta as a constant, we can avoid the - // floating point division and just compare after some integer ops. - int32_t delta = factorSize.width * aSize.height - aSize.width * factorSize.height; - int32_t maxDelta = (factorSize.height * aSize.height) >> 4; - if (delta > maxDelta || delta < -maxDelta) { - return aSize; - } - - // If the requested size is bigger than the native size, we actually need - // to grow the native size instead of shrinking it. - if (factorSize.width < aSize.width) { - do { - IntSize candidate(factorSize.width * 2, factorSize.height * 2); - if (!SurfaceCache::IsLegalSize(candidate)) { - break; - } - - factorSize = candidate; - } while (factorSize.width < aSize.width); - - return factorSize; - } - - // Otherwise we can find the best fit as normal. - } - // Start with the native size as the best first guess. IntSize bestSize = factorSize; factorSize.width /= 2; @@ -738,10 +674,6 @@ private: // True if all non-factor of 2 surfaces have been removed from the cache. Note // that this excludes unsubstitutable sizes. bool mFactor2Pruned; - - // True if the surfaces are produced from a vector image. If so, it must match - // the aspect ratio when using factor of 2 mode. - bool mIsVectorImage; }; /** @@ -828,10 +760,9 @@ public: // Locate the appropriate per-image cache. If there's not an existing cache // for this image, create it. - const ImageKey imageKey = aProvider->GetImageKey(); - RefPtr cache = GetImageCache(imageKey); + RefPtr cache = GetImageCache(aProvider->GetImageKey()); if (!cache) { - cache = new ImageSurfaceCache(imageKey); + cache = new ImageSurfaceCache; mImageCaches.Put(aProvider->GetImageKey(), cache); } @@ -1083,7 +1014,7 @@ public: { RefPtr cache = GetImageCache(aImageKey); if (!cache) { - cache = new ImageSurfaceCache(aImageKey); + cache = new ImageSurfaceCache; mImageCaches.Put(aImageKey, cache); } @@ -1699,30 +1630,5 @@ SurfaceCache::MaximumCapacity() return sInstance->MaximumCapacity(); } -/* static */ bool -SurfaceCache::IsLegalSize(const IntSize& aSize) -{ - // reject over-wide or over-tall images - const int32_t k64KLimit = 0x0000FFFF; - if (MOZ_UNLIKELY(aSize.width > k64KLimit || aSize.height > k64KLimit )) { - NS_WARNING("image too big"); - return false; - } - - // protect against invalid sizes - if (MOZ_UNLIKELY(aSize.height <= 0 || aSize.width <= 0)) { - return false; - } - - // check to make sure we don't overflow a 32-bit - CheckedInt32 requiredBytes = CheckedInt32(aSize.width) * - CheckedInt32(aSize.height) * 4; - if (MOZ_UNLIKELY(!requiredBytes.isValid())) { - NS_WARNING("width or height too large"); - return false; - } - return true; -} - } // namespace image } // namespace mozilla diff --git a/image/SurfaceCache.h b/image/SurfaceCache.h index f351b8e8f5ff..30a07723d5e3 100644 --- a/image/SurfaceCache.h +++ b/image/SurfaceCache.h @@ -443,11 +443,6 @@ struct SurfaceCache */ static size_t MaximumCapacity(); - /** - * @return true if the given size is valid. - */ - static bool IsLegalSize(const IntSize& aSize); - private: virtual ~SurfaceCache() = 0; // Forbid instantiation. }; diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index 92298ebc074c..597a3fd63169 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -807,21 +807,15 @@ VectorImage::GetFrameInternal(const IntSize& aSize, RefPtr()); } - // We don't allow large surfaces to be rasterized on the Draw and - // GetImageContainerAtSize paths, because those have alternatives. If we get - // here however, then we know it came from GetFrame(AtSize) and that path does - // not have any fallback method, so we don't check UseSurfaceCacheForSize. - RefPtr sourceSurface; - IntSize decodeSize; - Tie(sourceSurface, decodeSize) = + RefPtr sourceSurface = LookupCachedSurface(aSize, aSVGContext, aFlags); if (sourceSurface) { - return MakeTuple(ImgDrawResult::SUCCESS, decodeSize, std::move(sourceSurface)); + return MakeTuple(ImgDrawResult::SUCCESS, aSize, std::move(sourceSurface)); } if (mIsDrawing) { NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw"); - return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, decodeSize, + return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, aSize, RefPtr()); } @@ -830,8 +824,7 @@ VectorImage::GetFrameInternal(const IntSize& aSize, // flags, having an animation, etc). Otherwise CreateSurface will assume that // the caller is capable of drawing directly to its own draw target if we // cannot cache. - SVGDrawingParameters params(nullptr, decodeSize, aSize, - ImageRegion::Create(decodeSize), + SVGDrawingParameters params(nullptr, aSize, ImageRegion::Create(aSize), SamplingFilter::POINT, aSVGContext, mSVGDocumentWrapper->GetCurrentTime(), aFlags, 1.0); @@ -847,12 +840,12 @@ VectorImage::GetFrameInternal(const IntSize& aSize, CreateSurface(params, svgDrawable, didCache); if (!surface) { MOZ_ASSERT(!didCache); - return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, decodeSize, + return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, aSize, RefPtr()); } SendFrameComplete(didCache, params.flags); - return MakeTuple(ImgDrawResult::SUCCESS, decodeSize, std::move(surface)); + return MakeTuple(ImgDrawResult::SUCCESS, aSize, std::move(surface)); } //****************************************************************************** @@ -911,9 +904,7 @@ VectorImage::IsImageContainerAvailableAtSize(LayerManager* aManager, { // Since we only support image containers with WebRender, and it can handle // textures larger than the hw max texture size, we don't need to check aSize. - return !aSize.IsEmpty() && - UseSurfaceCacheForSize(aSize) && - IsImageContainerAvailable(aManager, aFlags); + return !aSize.IsEmpty() && IsImageContainerAvailable(aManager, aFlags); } //****************************************************************************** @@ -924,16 +915,15 @@ VectorImage::GetImageContainerAtSize(layers::LayerManager* aManager, uint32_t aFlags, layers::ImageContainer** aOutContainer) { - if (!UseSurfaceCacheForSize(aSize)) { - return ImgDrawResult::NOT_SUPPORTED; - } - Maybe newSVGContext; MaybeRestrictSVGContext(newSVGContext, aSVGContext, aFlags); - // The aspect ratio flag was already handled as part of the SVG context - // restriction above. - uint32_t flags = aFlags & ~(FLAG_FORCE_PRESERVEASPECTRATIO_NONE); + // Since we do not support high quality scaling with SVG, we mask it off so + // that container requests with and without it map to the same container. + // Similarly the aspect ratio flag was already handled as part of the SVG + // context restriction above. + uint32_t flags = aFlags & ~(FLAG_HIGH_QUALITY_SCALING | + FLAG_FORCE_PRESERVEASPECTRATIO_NONE); return GetImageContainerImpl(aManager, aSize, newSVGContext ? newSVGContext : aSVGContext, flags, aOutContainer); @@ -1012,13 +1002,10 @@ VectorImage::Draw(gfxContext* aContext, SendOnUnlockedDraw(aFlags); } - // We should bypass the cache when: - // - We are using a DrawTargetRecording because we prefer the drawing commands - // in general to the rasterized surface. This allows blob images to avoid - // rasterized SVGs with WebRender. - // - The size exceeds what we are will to cache as a rasterized surface. - if (aContext->GetDrawTarget()->GetBackendType() == BackendType::RECORDING || - !UseSurfaceCacheForSize(aSize)) { + // We should always bypass the cache when using DrawTargetRecording because + // we prefer the drawing commands in general to the rasterized surface. This + // allows blob images to avoid rasterized SVGs with WebRender. + if (aContext->GetDrawTarget()->GetBackendType() == BackendType::RECORDING) { aFlags |= FLAG_BYPASS_SURFACE_CACHE; } @@ -1034,19 +1021,18 @@ VectorImage::Draw(gfxContext* aContext, bool contextPaint = MaybeRestrictSVGContext(newSVGContext, aSVGContext, aFlags); - SVGDrawingParameters params(aContext, aSize, aSize, aRegion, aSamplingFilter, + SVGDrawingParameters params(aContext, aSize, aRegion, aSamplingFilter, newSVGContext ? newSVGContext : aSVGContext, animTime, aFlags, aOpacity); // If we have an prerasterized version of this image that matches the // drawing parameters, use that. - RefPtr sourceSurface; - Tie(sourceSurface, params.size) = + RefPtr sourceSurface = LookupCachedSurface(aSize, params.svgContext, aFlags); if (sourceSurface) { - RefPtr drawable = - new gfxSurfaceDrawable(sourceSurface, params.size); - Show(drawable, params); + RefPtr svgDrawable = + new gfxSurfaceDrawable(sourceSurface, sourceSurface->GetSize()); + Show(svgDrawable, params); return ImgDrawResult::SUCCESS; } @@ -1090,56 +1076,29 @@ VectorImage::CreateSVGDrawable(const SVGDrawingParameters& aParams) return svgDrawable.forget(); } -bool -VectorImage::UseSurfaceCacheForSize(const IntSize& aSize) const -{ - int32_t maxSizeKB = gfxPrefs::ImageCacheMaxRasterizedSVGThresholdKB(); - if (maxSizeKB <= 0) { - return true; - } - - if (!SurfaceCache::IsLegalSize(aSize)) { - return false; - } - - // With factor of 2 mode, we should be willing to use a surface which is up - // to twice the width, and twice the height, of the maximum sized surface - // before switching to drawing to the target directly. That means the size in - // KB works out to be: - // width * height * 4 [bytes/pixel] * / 1024 [bytes/KB] <= 2 * 2 * maxSizeKB - return aSize.width * aSize.height / 1024 <= maxSizeKB; -} - -Tuple, IntSize> +already_AddRefed VectorImage::LookupCachedSurface(const IntSize& aSize, const Maybe& aSVGContext, uint32_t aFlags) { // If we're not allowed to use a cached surface, don't attempt a lookup. if (aFlags & FLAG_BYPASS_SURFACE_CACHE) { - return MakeTuple(RefPtr(), aSize); + return nullptr; } // We don't do any caching if we have animation, so don't bother with a lookup // in this case either. if (mHaveAnimations) { - return MakeTuple(RefPtr(), aSize); + return nullptr; } - LookupResult result(MatchType::NOT_FOUND); - SurfaceKey surfaceKey = VectorSurfaceKey(aSize, aSVGContext); - if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) { - result = SurfaceCache::Lookup(ImageKey(this), surfaceKey); - } else { - result = SurfaceCache::LookupBestMatch(ImageKey(this), surfaceKey); - } + LookupResult result = + SurfaceCache::Lookup(ImageKey(this), + VectorSurfaceKey(aSize, aSVGContext)); - IntSize rasterSize = result.SuggestedSize().IsEmpty() - ? aSize : result.SuggestedSize(); - MOZ_ASSERT(result.Type() != MatchType::SUBSTITUTE_BECAUSE_PENDING); - if (!result || result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND) { - // No matching surface, or the OS freed the volatile buffer. - return MakeTuple(RefPtr(), rasterSize); + MOZ_ASSERT(result.SuggestedSize().IsEmpty(), "SVG should not substitute!"); + if (!result) { + return nullptr; // No matching surface, or the OS freed the volatile buffer. } RefPtr sourceSurface = result.Surface()->GetSourceSurface(); @@ -1147,10 +1106,10 @@ VectorImage::LookupCachedSurface(const IntSize& aSize, // Something went wrong. (Probably a GPU driver crash or device reset.) // Attempt to recover. RecoverFromLossOfSurfaces(); - return MakeTuple(RefPtr(), rasterSize); + return nullptr; } - return MakeTuple(std::move(sourceSurface), rasterSize); + return sourceSurface.forget(); } already_AddRefed @@ -1230,15 +1189,7 @@ VectorImage::CreateSurface(const SVGDrawingParameters& aParams, SurfaceKey surfaceKey = VectorSurfaceKey(aParams.size, aParams.svgContext); NotNull> provider = MakeNotNull(ImageKey(this), surfaceKey, frame); - - if (SurfaceCache::Insert(provider) == InsertOutcome::SUCCESS && - aParams.size != aParams.drawSize) { - // We created a new surface that wasn't the size we requested, which means - // we entered factor-of-2 mode. We should purge any surfaces we no longer - // need rather than waiting for the cache to expire them. - SurfaceCache::PruneImage(ImageKey(this)); - } - + SurfaceCache::Insert(provider); return surface.forget(); } @@ -1273,21 +1224,10 @@ VectorImage::SendFrameComplete(bool aDidCache, uint32_t aFlags) void VectorImage::Show(gfxDrawable* aDrawable, const SVGDrawingParameters& aParams) { - // The surface size may differ from the size at which we wish to draw. As - // such, we may need to adjust the context/region to take this into account. - gfxContextMatrixAutoSaveRestore saveMatrix(aParams.context); - ImageRegion region(aParams.region); - if (aParams.drawSize != aParams.size) { - gfx::Size scale(double(aParams.drawSize.width) / aParams.size.width, - double(aParams.drawSize.height) / aParams.size.height); - aParams.context->Multiply(gfxMatrix::Scaling(scale.width, scale.height)); - region.Scale(1.0 / scale.width, 1.0 / scale.height); - } - MOZ_ASSERT(aDrawable, "Should have a gfxDrawable by now"); gfxUtils::DrawPixelSnapped(aParams.context, aDrawable, SizeDouble(aParams.size), - region, + aParams.region, SurfaceFormat::B8G8R8A8, aParams.samplingFilter, aParams.flags, aParams.opacity, false); diff --git a/image/VectorImage.h b/image/VectorImage.h index 114de1c7a956..bbc5ac6e12ea 100644 --- a/image/VectorImage.h +++ b/image/VectorImage.h @@ -92,12 +92,8 @@ private: const IntSize& aSize, uint32_t aFlags) override; - /** - * Attempt to find a matching cached surface in the SurfaceCache. Returns the - * cached surface, if found, and the size to rasterize at, if applicable. - * If we cannot rasterize, it will be the requested size to draw at (aSize). - */ - Tuple, IntSize> + /// Attempt to find a matching cached surface in the SurfaceCache. + already_AddRefed LookupCachedSurface(const IntSize& aSize, const Maybe& aSVGContext, uint32_t aFlags); @@ -110,9 +106,6 @@ private: already_AddRefed CreateSVGDrawable(const SVGDrawingParameters& aParams); - /// Returns true if we use the surface cache to store rasterized copies. - bool UseSurfaceCacheForSize(const IntSize& aSize) const; - /// Rasterize the SVG into a surface. aWillCache will be set to whether or /// not the new surface was put into the cache. already_AddRefed diff --git a/image/imgFrame.cpp b/image/imgFrame.cpp index 8cce3e2af54c..03822f581293 100644 --- a/image/imgFrame.cpp +++ b/image/imgFrame.cpp @@ -7,7 +7,6 @@ #include "imgFrame.h" #include "ImageRegion.h" #include "ShutdownTracker.h" -#include "SurfaceCache.h" #include "prenv.h" @@ -158,13 +157,38 @@ ClearSurface(DataSourceSurface* aSurface, const IntSize& aSize, SurfaceFormat aF return true; } +// Returns true if an image of aWidth x aHeight is allowed and legal. +static bool +AllowedImageSize(int32_t aWidth, int32_t aHeight) +{ + // reject over-wide or over-tall images + const int32_t k64KLimit = 0x0000FFFF; + if (MOZ_UNLIKELY(aWidth > k64KLimit || aHeight > k64KLimit )) { + NS_WARNING("image too big"); + return false; + } + + // protect against invalid sizes + if (MOZ_UNLIKELY(aHeight <= 0 || aWidth <= 0)) { + return false; + } + + // check to make sure we don't overflow a 32-bit + CheckedInt32 requiredBytes = CheckedInt32(aWidth) * CheckedInt32(aHeight) * 4; + if (MOZ_UNLIKELY(!requiredBytes.isValid())) { + NS_WARNING("width or height too large"); + return false; + } + return true; +} + static bool AllowedImageAndFrameDimensions(const nsIntSize& aImageSize, const nsIntRect& aFrameRect) { - if (!SurfaceCache::IsLegalSize(aImageSize)) { + if (!AllowedImageSize(aImageSize.width, aImageSize.height)) { return false; } - if (!SurfaceCache::IsLegalSize(aFrameRect.Size())) { + if (!AllowedImageSize(aFrameRect.Width(), aFrameRect.Height())) { return false; } nsIntRect imageRect(0, 0, aImageSize.width, aImageSize.height); @@ -313,7 +337,7 @@ imgFrame::InitWithDrawable(gfxDrawable* aDrawable, { // Assert for properties that should be verified by decoders, // warn for properties related to bad content. - if (!SurfaceCache::IsLegalSize(aSize)) { + if (!AllowedImageSize(aSize.width, aSize.height)) { NS_WARNING("Should have legal image size"); mAborted = true; return NS_ERROR_FAILURE; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index f2c786153dad..d72bb56353e9 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4620,10 +4620,6 @@ pref("image.animated.resume-from-last-displayed", true); // same data at different sizes. pref("image.cache.factor2.threshold-surfaces", 4); -// Maximum number of pixels in either dimension that we are willing to upscale -// an SVG to when we are in "factor of 2" mode. -pref("image.cache.max-rasterized-svg-threshold-kb", 92160); - // The maximum size, in bytes, of the decoded images we cache pref("image.cache.size", 5242880);