mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 12:35:58 +00:00
Bug 1260324. Don't draw garbage to the screen if an image doesn't happen to be decoded. r=seth
Layout has been using imgIContainer::IsOpaque to determine if the image will draw opaquely to all pixels it covers, and doing culling based on this. However imgIContainer::IsOpaque doesn't guarantee anything. It only describes if the image, when in a decoded state, has all opaque pixels. So if the image doesn't have fully decoded frames around (because they got discarded) it may not draw opaquely to all of its pixels. So we create a new function that first checks if there is a fully decoded frame.
This commit is contained in:
parent
a7e6714dd9
commit
05dc5b9ede
@ -195,10 +195,8 @@ DynamicImage::GetFrameAtSize(const IntSize& aSize,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
DynamicImage::IsOpaque()
|
||||
DynamicImage::WillDrawOpaqueNow()
|
||||
{
|
||||
// XXX(seth): For performance reasons it'd be better to return true here, but
|
||||
// I'm not sure how we can guarantee it for an arbitrary gfxDrawable.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -185,9 +185,9 @@ ImageWrapper::GetFrameAtSize(const IntSize& aSize,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
ImageWrapper::IsOpaque()
|
||||
ImageWrapper::WillDrawOpaqueNow()
|
||||
{
|
||||
return mInnerImage->IsOpaque();
|
||||
return mInnerImage->WillDrawOpaqueNow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
|
@ -89,7 +89,7 @@ OrientedImage::GetFrame(uint32_t aWhichFrame,
|
||||
|
||||
// Determine an appropriate format for the surface.
|
||||
gfx::SurfaceFormat surfaceFormat;
|
||||
if (InnerImage()->IsOpaque()) {
|
||||
if (InnerImage()->WillDrawOpaqueNow()) {
|
||||
surfaceFormat = gfx::SurfaceFormat::B8G8R8X8;
|
||||
} else {
|
||||
surfaceFormat = gfx::SurfaceFormat::B8G8R8A8;
|
||||
|
@ -377,7 +377,7 @@ RasterImage::LookupFrame(const IntSize& aSize,
|
||||
return Move(result.Surface());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
bool
|
||||
RasterImage::IsOpaque()
|
||||
{
|
||||
if (mError) {
|
||||
@ -395,6 +395,39 @@ RasterImage::IsOpaque()
|
||||
return !(progress & FLAG_HAS_TRANSPARENCY);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
RasterImage::WillDrawOpaqueNow()
|
||||
{
|
||||
if (!IsOpaque()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mAnimationState) {
|
||||
// We never discard frames of animated images.
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we are not locked our decoded data could get discard at any time (ie
|
||||
// between the call to this function and when we are asked to draw), so we
|
||||
// have to return false if we are unlocked.
|
||||
if (IsUnlocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LookupResult result =
|
||||
SurfaceCache::LookupBestMatch(ImageKey(this),
|
||||
RasterSurfaceKey(mSize,
|
||||
DefaultSurfaceFlags(),
|
||||
PlaybackType::eStatic));
|
||||
MatchType matchType = result.Type();
|
||||
if (matchType == MatchType::NOT_FOUND || matchType == MatchType::PENDING ||
|
||||
!result.Surface()->IsFinished()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::OnSurfaceDiscarded()
|
||||
{
|
||||
|
@ -484,6 +484,8 @@ private: // data
|
||||
// Helpers
|
||||
bool CanDiscard();
|
||||
|
||||
bool IsOpaque();
|
||||
|
||||
protected:
|
||||
explicit RasterImage(ImageURL* aURI = nullptr);
|
||||
|
||||
|
@ -678,7 +678,7 @@ VectorImage::GetFirstFrameDelay()
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
VectorImage::IsOpaque()
|
||||
VectorImage::WillDrawOpaqueNow()
|
||||
{
|
||||
return false; // In general, SVG content is not opaque.
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
nsresult aResult,
|
||||
bool aLastPart) override;
|
||||
|
||||
void OnSurfaceDiscarded() override;
|
||||
virtual void OnSurfaceDiscarded() override;
|
||||
|
||||
/**
|
||||
* Callback for SVGRootRenderingObserver.
|
||||
|
@ -264,9 +264,12 @@ interface imgIContainer : nsISupports
|
||||
in uint32_t aFlags);
|
||||
|
||||
/**
|
||||
* Whether this image is opaque (i.e., needs a background painted behind it).
|
||||
* Returns true if this image will draw opaquely right now if asked to draw
|
||||
* with FLAG_HIGH_QUALITY_SCALING and otherwise default flags. If this image
|
||||
* (when decoded) is opaque but no decoded frames are available then
|
||||
* willDrawOpaqueNow will return false.
|
||||
*/
|
||||
[notxpcom] boolean isOpaque();
|
||||
[noscript, notxpcom] boolean willDrawOpaqueNow();
|
||||
|
||||
/**
|
||||
* @return true if getImageContainer() is expected to return a valid
|
||||
|
@ -1634,7 +1634,7 @@ nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
bool* aSnap)
|
||||
{
|
||||
*aSnap = false;
|
||||
if (mImage && mImage->IsOpaque()) {
|
||||
if (mImage && mImage->WillDrawOpaqueNow()) {
|
||||
const nsRect frameContentBox = GetBounds(aSnap);
|
||||
return GetDestRect().Intersect(frameContentBox);
|
||||
}
|
||||
|
@ -2218,7 +2218,7 @@ nsStyleImage::IsOpaque() const
|
||||
MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
|
||||
|
||||
// Check if the crop region of the image is opaque.
|
||||
if (imageContainer->IsOpaque()) {
|
||||
if (imageContainer->WillDrawOpaqueNow()) {
|
||||
if (!mCropRect) {
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user