зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1456558) for crashtest assertion failures on a CLOSED TREE
Backed out changeset 70d8f11cf6e8 (bug 1456558) Backed out changeset af9fc3daf97c (bug 1456558) Backed out changeset f209a9d848f4 (bug 1456558)
This commit is contained in:
Родитель
73e08d1bf5
Коммит
3805f6a285
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
|
||||
GetFrameInternal(const gfx::IntSize& aSize,
|
||||
const Maybe<SVGImageContext>& aSVGContext,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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<SVGImageContext>& 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<SVGImageContext>& svgContext;
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <algorithm>
|
||||
#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<CachedSurface*> current = WrapNotNull(first.UserData());
|
||||
Image* image = static_cast<Image*>(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<ImageSurfaceCache> cache = GetImageCache(imageKey);
|
||||
RefPtr<ImageSurfaceCache> cache = GetImageCache(aProvider->GetImageKey());
|
||||
if (!cache) {
|
||||
cache = new ImageSurfaceCache(imageKey);
|
||||
cache = new ImageSurfaceCache;
|
||||
mImageCaches.Put(aProvider->GetImageKey(), cache);
|
||||
}
|
||||
|
||||
|
@ -1083,7 +1014,7 @@ public:
|
|||
{
|
||||
RefPtr<ImageSurfaceCache> 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
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
|
|
|
@ -807,21 +807,15 @@ VectorImage::GetFrameInternal(const IntSize& aSize,
|
|||
RefPtr<SourceSurface>());
|
||||
}
|
||||
|
||||
// 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> sourceSurface;
|
||||
IntSize decodeSize;
|
||||
Tie(sourceSurface, decodeSize) =
|
||||
RefPtr<SourceSurface> 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<SourceSurface>());
|
||||
}
|
||||
|
||||
|
@ -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<SourceSurface>());
|
||||
}
|
||||
|
||||
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<SVGImageContext> 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> sourceSurface;
|
||||
Tie(sourceSurface, params.size) =
|
||||
RefPtr<SourceSurface> sourceSurface =
|
||||
LookupCachedSurface(aSize, params.svgContext, aFlags);
|
||||
if (sourceSurface) {
|
||||
RefPtr<gfxDrawable> drawable =
|
||||
new gfxSurfaceDrawable(sourceSurface, params.size);
|
||||
Show(drawable, params);
|
||||
RefPtr<gfxDrawable> 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<RefPtr<SourceSurface>, IntSize>
|
||||
already_AddRefed<SourceSurface>
|
||||
VectorImage::LookupCachedSurface(const IntSize& aSize,
|
||||
const Maybe<SVGImageContext>& 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<SourceSurface>(), 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<SourceSurface>(), 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<SourceSurface>(), 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> 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<SourceSurface>(), rasterSize);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return MakeTuple(std::move(sourceSurface), rasterSize);
|
||||
return sourceSurface.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<SourceSurface>
|
||||
|
@ -1230,15 +1189,7 @@ VectorImage::CreateSurface(const SVGDrawingParameters& aParams,
|
|||
SurfaceKey surfaceKey = VectorSurfaceKey(aParams.size, aParams.svgContext);
|
||||
NotNull<RefPtr<ISurfaceProvider>> provider =
|
||||
MakeNotNull<SimpleSurfaceProvider*>(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);
|
||||
|
|
|
@ -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<RefPtr<SourceSurface>, IntSize>
|
||||
/// Attempt to find a matching cached surface in the SurfaceCache.
|
||||
already_AddRefed<SourceSurface>
|
||||
LookupCachedSurface(const IntSize& aSize,
|
||||
const Maybe<SVGImageContext>& aSVGContext,
|
||||
uint32_t aFlags);
|
||||
|
@ -110,9 +106,6 @@ private:
|
|||
already_AddRefed<gfxDrawable>
|
||||
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<SourceSurface>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче