Bug 852754 - Part 1: Share the code for limiting scale factors to all image types. r=mstange

This commit is contained in:
Matt Woodrow 2016-04-07 18:52:35 +12:00
Родитель 8232d31724
Коммит 46ff4c4fc7
10 изменённых файлов: 151 добавлений и 192 удалений

Просмотреть файл

@ -5404,21 +5404,6 @@ nsImageRenderer::IsAnimatedImage()
return false;
}
bool
nsImageRenderer::IsContainerAvailable(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
{
if (mType != eStyleImageType_Image || !mImageContainer) {
return false;
}
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
return mImageContainer->IsImageContainerAvailable(aManager, flags);
}
already_AddRefed<imgIContainer>
nsImageRenderer::GetImage()
{

Просмотреть файл

@ -251,16 +251,6 @@ public:
bool IsRasterImage();
bool IsAnimatedImage();
/**
* @return true if this nsImageRenderer wraps an image which has an
* ImageContainer available.
*
* If IsContainerAvailable() returns true, GetImage() will return a non-null
* imgIContainer which callers can use to retrieve the ImageContainer.
*/
bool IsContainerAvailable(LayerManager* aManager,
nsDisplayListBuilder* aBuilder);
/// Retrieves the image associated with this nsImageRenderer, if there is one.
already_AddRefed<imgIContainer> GetImage();

Просмотреть файл

@ -2309,32 +2309,33 @@ nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilde
: nsDisplayImageContainer(aBuilder, aFrame)
, mBackgroundStyle(aBackgroundStyle)
, mLayer(aLayer)
, mIsRasterImage(false)
{
MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
mBounds = GetBoundsInternal(aBuilder);
mDestArea = GetDestAreaInternal(aBuilder);
if (ShouldFixToViewport(aBuilder)) {
mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(this);
}
}
nsRect
nsDisplayBackgroundImage::GetDestAreaInternal(nsDisplayListBuilder* aBuilder)
{
if (!mBackgroundStyle) {
return nsRect();
}
nsPresContext* presContext = mFrame->PresContext();
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
const nsStyleImageLayers::Layer& layer = mBackgroundStyle->mImage.mLayers[mLayer];
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
nsBackgroundLayerState state =
nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags,
borderArea, borderArea, layer);
return state.mDestArea;
mFillRect = state.mFillArea;
mDestRect = state.mDestArea;
nsImageRenderer* imageRenderer = &state.mImageRenderer;
// We only care about images here, not gradients.
if (imageRenderer->IsRasterImage()) {
mIsRasterImage = true;
mImage = imageRenderer->GetImage();
}
}
nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
@ -2566,24 +2567,16 @@ nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuil
if (mBackgroundStyle->mImage.mLayers.Length() != 1)
return false;
nsPresContext* presContext = mFrame->PresContext();
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
if (layer.mAttachment != NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED)
return false;
nsBackgroundLayerState state =
nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags,
borderArea, aClipRect, layer);
nsImageRenderer* imageRenderer = &state.mImageRenderer;
// We only care about images here, not gradients.
if (!imageRenderer->IsRasterImage())
if (!mIsRasterImage)
return false;
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
*aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
*aDestRect = nsLayoutUtils::RectToGfxRect(mFillRect, appUnitsPerDevPixel);
return true;
}
@ -2618,51 +2611,35 @@ nsDisplayBackgroundImage::CanOptimizeToImageLayer(LayerManager* aManager,
return false;
}
nsPresContext* presContext = mFrame->PresContext();
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
nsBackgroundLayerState state =
nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags,
borderArea, borderArea, layer);
nsImageRenderer* imageRenderer = &state.mImageRenderer;
// We only care about images here, not gradients.
if (!imageRenderer->IsRasterImage()) {
return false;
}
if (!imageRenderer->IsContainerAvailable(aManager, aBuilder)) {
// The image is not ready to be made into a layer yet.
return false;
}
// We currently can't handle tiled backgrounds.
if (!state.mDestArea.Contains(state.mFillArea)) {
if (!mDestRect.Contains(mFillRect)) {
return false;
}
// For 'contain' and 'cover', we allow any pixel of the image to be sampled
// because there isn't going to be any spriting/atlasing going on.
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
bool allowPartialImages =
(layer.mSize.mWidthType == nsStyleImageLayers::Size::eContain ||
layer.mSize.mWidthType == nsStyleImageLayers::Size::eCover);
if (!allowPartialImages && !state.mFillArea.Contains(state.mDestArea)) {
if (!allowPartialImages && !mFillRect.Contains(mDestRect)) {
return false;
}
// XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to
// layer pixel boundaries. This should be OK for now.
return nsDisplayImageContainer::CanOptimizeToImageLayer(aManager, aBuilder);
}
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
mImageLayerDestRect =
LayoutDeviceRect::FromAppUnits(state.mDestArea, appUnitsPerDevPixel);
nsRect
nsDisplayBackgroundImage::GetDestRect()
{
return mDestRect;
}
// Ok, we can turn this into a layer if needed.
mImage = imageRenderer->GetImage();
MOZ_ASSERT(mImage);
return true;
already_AddRefed<imgIContainer>
nsDisplayBackgroundImage::GetImage()
{
nsCOMPtr<imgIContainer> image = mImage;
return image.forget();
}
already_AddRefed<ImageContainer>
@ -2747,8 +2724,11 @@ nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
mImage->GetWidth(&imageWidth);
mImage->GetHeight(&imageHeight);
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(GetDestRect(), appUnitsPerDevPixel);
const LayerRect destLayerRect = mImageLayerDestRect * aParameters.Scale();
const LayerRect destLayerRect = destRect * aParameters.Scale();
// Calculate the scaling factor for the frame.
const gfxSize scale = gfxSize(destLayerRect.width / imageWidth,
@ -2821,11 +2801,15 @@ nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer,
IntSize containerSize = aLayer->GetContainer()
? aLayer->GetContainer()->GetCurrentSize()
: IntSize(imageWidth, imageHeight);
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
const LayoutDeviceRect destRect =
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
const LayoutDevicePoint p = mImageLayerDestRect.TopLeft();
const LayoutDevicePoint p = destRect.TopLeft();
Matrix transform = Matrix::Translation(p.x, p.y);
transform.PreScale(mImageLayerDestRect.width / containerSize.width,
mImageLayerDestRect.height / containerSize.height);
transform.PreScale(destRect.width / containerSize.width,
destRect.height / containerSize.height);
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
}
@ -3022,7 +3006,7 @@ void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* a
}
return;
}
if (!mDestArea.IsEqualInterior(geometry->mDestArea)) {
if (!mDestRect.IsEqualInterior(geometry->mDestRect)) {
// Dest area changed in a way that could cause everything to change,
// so invalidate everything (both old and new painting areas).
aInvalidRegion->Or(bounds, geometry->mBounds);
@ -3248,6 +3232,50 @@ nsDisplayThemedBackground::GetBoundsInternal() {
return r + ToReferenceFrame();
}
bool
nsDisplayImageContainer::CanOptimizeToImageLayer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
{
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
nsCOMPtr<imgIContainer> image = GetImage();
if (!image) {
return false;
}
if (!image->IsImageContainerAvailable(aManager, flags)) {
return false;
}
int32_t imageWidth;
int32_t imageHeight;
image->GetWidth(&imageWidth);
image->GetHeight(&imageHeight);
if (imageWidth == 0 || imageHeight == 0) {
NS_ASSERTION(false, "invalid image size");
return false;
}
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
const LayoutDeviceRect destRect =
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
// Calculate the scaling factor for the frame.
const gfxSize scale = gfxSize(destRect.width / imageWidth,
destRect.height / imageHeight);
if (scale.width < 0.2 || scale.height < 0.2) {
// This would look awful as long as we can't use high-quality downscaling
// for image layers (bug 803703), so don't turn this into an image layer.
return false;
}
return true;
}
void
nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder,
float aOpacity,

Просмотреть файл

@ -2323,13 +2323,17 @@ public:
* CanOptimizeToImageLayer() first and it returned true.
*/
virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder) = 0;
nsDisplayListBuilder* aBuilder);
virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder) = 0;
virtual void ConfigureLayer(ImageLayer* aLayer,
const ContainerLayerParameters& aParameters) = 0;
virtual already_AddRefed<imgIContainer> GetImage() = 0;
virtual nsRect GetDestRect() = 0;
virtual bool SupportsOptimizingToImage() override { return true; }
};
@ -2698,11 +2702,6 @@ public:
*/
nsRect GetPositioningArea();
/**
* Return the destination area of one instance of the image.
*/
nsRect GetDestArea() const { return mDestArea; }
/**
* Returns true if existing rendered pixels of this display item may need
* to be redrawn if the positioning area size changes but its position does
@ -2723,6 +2722,8 @@ public:
virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder) override;
virtual already_AddRefed<imgIContainer> GetImage() override;
virtual nsRect GetDestRect() override;
virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
nsDisplayListBuilder *aBuilder) override;
virtual void ConfigureLayer(ImageLayer* aLayer,
@ -2743,7 +2744,6 @@ protected:
gfxRect* aDestRect);
bool IsNonEmptyFixedImage() const;
nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder);
nsRect GetDestAreaInternal(nsDisplayListBuilder* aBuilder);
void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
const nsRect& aBounds, nsRect* aClipRect);
@ -2763,11 +2763,12 @@ protected:
const nsStyleBackground* mBackgroundStyle;
nsCOMPtr<imgIContainer> mImage;
RefPtr<ImageContainer> mImageContainer;
LayoutDeviceRect mImageLayerDestRect;
nsRect mFillRect;
nsRect mDestRect;
/* Bounds of this display item */
nsRect mBounds;
nsRect mDestArea;
uint32_t mLayer;
bool mIsRasterImage;
};

Просмотреть файл

@ -63,7 +63,7 @@ nsDisplayBackgroundGeometry::nsDisplayBackgroundGeometry(nsDisplayBackgroundImag
: nsDisplayItemGeometry(aItem, aBuilder)
, nsImageGeometryMixin(aItem, aBuilder)
, mPositioningArea(aItem->GetPositioningArea())
, mDestArea(aItem->GetDestArea())
, mDestRect(aItem->GetDestRect())
{}
void
@ -71,7 +71,7 @@ nsDisplayBackgroundGeometry::MoveBy(const nsPoint& aOffset)
{
nsDisplayItemGeometry::MoveBy(aOffset);
mPositioningArea.MoveBy(aOffset);
mDestArea.MoveBy(aOffset);
mDestRect.MoveBy(aOffset);
}
nsDisplayThemedBackgroundGeometry::nsDisplayThemedBackgroundGeometry(nsDisplayThemedBackground* aItem,

Просмотреть файл

@ -194,7 +194,7 @@ public:
virtual void MoveBy(const nsPoint& aOffset) override;
nsRect mPositioningArea;
nsRect mDestArea;
nsRect mDestRect;
};
class nsDisplayThemedBackgroundGeometry : public nsDisplayItemGeometry

Просмотреть файл

@ -1524,45 +1524,6 @@ nsDisplayImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
}
bool
nsDisplayImage::CanOptimizeToImageLayer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
{
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
if (!mImage->IsImageContainerAvailable(aManager, flags)) {
return false;
}
int32_t imageWidth;
int32_t imageHeight;
mImage->GetWidth(&imageWidth);
mImage->GetHeight(&imageHeight);
if (imageWidth == 0 || imageHeight == 0) {
NS_ASSERTION(false, "invalid image size");
return false;
}
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
const LayoutDeviceRect destRect =
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
// Calculate the scaling factor for the frame.
const gfxSize scale = gfxSize(destRect.width / imageWidth,
destRect.height / imageHeight);
if (scale.width < 0.2 || scale.height < 0.2) {
// This would look awful as long as we can't use high-quality downscaling
// for image layers (bug 803703), so don't turn this into an image layer.
return false;
}
return true;
}
already_AddRefed<ImageContainer>
nsDisplayImage::GetContainer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
@ -1574,14 +1535,18 @@ nsDisplayImage::GetContainer(LayerManager* aManager,
return mImage->GetImageContainer(aManager, flags);
}
already_AddRefed<imgIContainer>
nsDisplayImage::GetImage()
{
nsCOMPtr<imgIContainer> image = mImage;
return image.forget();
}
nsRect
nsDisplayImage::GetDestRect(bool* aSnap)
nsDisplayImage::GetDestRect()
{
bool snap = true;
const nsRect frameContentBox = GetBounds(&snap);
if (aSnap) {
*aSnap = snap;
}
nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
return imageFrame->PredictedDestRect(frameContentBox);

Просмотреть файл

@ -428,8 +428,7 @@ public:
virtual void Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) override;
virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder) override;
virtual already_AddRefed<imgIContainer> GetImage() override;
/**
* Returns an ImageContainer for this image if the image type
@ -442,7 +441,7 @@ public:
* @return The dest rect we'll use when drawing this image, in app units.
* Not necessarily contained in this item's bounds.
*/
nsRect GetDestRect(bool* aSnap = nullptr);
virtual nsRect GetDestRect() override;
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,

Просмотреть файл

@ -450,17 +450,10 @@ nsDisplayXULImage::ConfigureLayer(ImageLayer* aLayer,
{
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
nsRect clientRect;
imageFrame->GetClientRect(clientRect);
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
const LayoutDeviceRect destRect =
LayoutDeviceRect::FromAppUnits(clientRect + ToReferenceFrame(), factor);
LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
nsCOMPtr<imgIContainer> imgCon;
imageFrame->mImageRequest->GetImage(getter_AddRefs(imgCon));
nsCOMPtr<imgIContainer> imgCon = GetImage();
int32_t imageWidth;
int32_t imageHeight;
imgCon->GetWidth(&imageWidth);
@ -503,30 +496,47 @@ bool
nsDisplayXULImage::CanOptimizeToImageLayer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
{
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
if (!imageFrame->CanOptimizeToImageLayer()) {
return false;
}
return static_cast<nsImageBoxFrame*>(mFrame)
->IsImageContainerAvailable(aManager, flags);
return nsDisplayImageContainer::CanOptimizeToImageLayer(aManager, aBuilder);
}
bool
nsImageBoxFrame::IsImageContainerAvailable(LayerManager* aManager,
uint32_t aFlags)
already_AddRefed<imgIContainer>
nsDisplayXULImage::GetImage()
{
bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
if (hasSubRect || !mImageRequest) {
return false;
nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
if (!imageFrame->mImageRequest) {
return nullptr;
}
nsCOMPtr<imgIContainer> imgCon;
mImageRequest->GetImage(getter_AddRefs(imgCon));
if (!imgCon) {
imageFrame->mImageRequest->GetImage(getter_AddRefs(imgCon));
return imgCon.forget();
}
nsRect
nsDisplayXULImage::GetDestRect()
{
nsImageBoxFrame* imageFrame = static_cast<nsImageBoxFrame*>(mFrame);
nsRect clientRect;
imageFrame->GetClientRect(clientRect);
return clientRect + ToReferenceFrame();
}
bool
nsImageBoxFrame::CanOptimizeToImageLayer()
{
bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
if (hasSubRect) {
return false;
}
return imgCon->IsImageContainerAvailable(aManager, aFlags);
return true;
}
already_AddRefed<ImageContainer>
@ -537,30 +547,11 @@ nsDisplayXULImage::GetContainer(LayerManager* aManager,
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager, flags);
}
already_AddRefed<ImageContainer>
nsImageBoxFrame::GetContainer(LayerManager* aManager, uint32_t aFlags)
{
MOZ_ASSERT(IsImageContainerAvailable(aManager, aFlags),
"Should call IsImageContainerAvailable and get true before "
"calling GetContainer");
if (!mImageRequest) {
MOZ_ASSERT_UNREACHABLE("mImageRequest should be available if "
"IsImageContainerAvailable returned true");
return nullptr;
nsCOMPtr<imgIContainer> image = GetImage();
if (image) {
return image->GetImageContainer(aManager, flags);
}
nsCOMPtr<imgIContainer> imgCon;
mImageRequest->GetImage(getter_AddRefs(imgCon));
if (!imgCon) {
MOZ_ASSERT_UNREACHABLE("An imgIContainer should be available if "
"IsImageContainerAvailable returned true");
return nullptr;
}
return imgCon->GetImageContainer(aManager, aFlags);
return nullptr;
}

Просмотреть файл

@ -96,9 +96,7 @@ public:
const nsRect& aDirtyRect,
nsPoint aPt, uint32_t aFlags);
bool IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags);
already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
uint32_t aFlags);
bool CanOptimizeToImageLayer();
protected:
explicit nsImageBoxFrame(nsStyleContext* aContext);
@ -146,6 +144,8 @@ public:
nsDisplayListBuilder* aBuilder) override;
virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder) override;
virtual already_AddRefed<imgIContainer> GetImage() override;
virtual nsRect GetDestRect() override;
virtual void ConfigureLayer(ImageLayer* aLayer,
const ContainerLayerParameters& aParameters) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override