author | Seth Fowler <mark.seth.fowler@gmail.com> |
Wed, 13 May 2015 00:23:46 -0700 | |
changeset 243654 | c0654f3b986de3687163c5e2de8e39250414f9d6 |
parent 243653 | 66d87284ab5c18499d3e10b3134b486678975ea1 |
child 243655 | 54f2b7d9725a96d920b1638fc5cb6470865e4ce2 |
push id | 28744 |
push user | kwierso@gmail.com |
push date | Wed, 13 May 2015 18:12:16 +0000 |
treeherder | mozilla-central@324c3423deaf [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | tn |
bugs | 1163878 |
milestone | 41.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -345,21 +345,27 @@ public: mMaybeHitRegion.Or(mMaybeHitRegion, aEventRegions->MaybeHitRegion()); mDispatchToContentHitRegion.Or(mDispatchToContentHitRegion, aEventRegions->DispatchToContentHitRegion()); mNoActionRegion.Or(mNoActionRegion, aEventRegions->NoActionRegion()); mHorizontalPanRegion.Or(mHorizontalPanRegion, aEventRegions->HorizontalPanRegion()); mVerticalPanRegion.Or(mVerticalPanRegion, aEventRegions->VerticalPanRegion()); } /** - * If this represents only a nsDisplayImage, and the image type - * supports being optimized to an ImageLayer (TYPE_RASTER only) returns - * an ImageContainer for the image. + * If this represents only a nsDisplayImage, and the image type supports being + * optimized to an ImageLayer, returns true. */ - already_AddRefed<ImageContainer> CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder); + bool CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder); + + /** + * If this represents only a nsDisplayImage, and the image type supports being + * optimized to an ImageLayer, returns an ImageContainer for the underlying + * image if one is available. + */ + already_AddRefed<ImageContainer> GetContainerForImageLayer(nsDisplayListBuilder* aBuilder); bool VisibleAboveRegionIntersects(const nsIntRect& aRect) const { return mVisibleAboveRegion.Intersects(aRect); } bool VisibleAboveRegionIntersects(const nsIntRegion& aRegion) const { return !mVisibleAboveRegion.Intersect(aRegion).IsEmpty(); } bool VisibleRegionIntersects(const nsIntRect& aRect) const { return mVisibleRegion.Intersects(aRect); } @@ -1046,16 +1052,29 @@ protected: * invalidate the layer for layer pixel alignment changes if necessary. */ void PreparePaintedLayerForUse(PaintedLayer* aLayer, PaintedDisplayItemLayerUserData* aData, const nsIFrame* aAnimatedGeometryRoot, const nsIFrame* aReferenceFrame, const nsPoint& aTopLeft, bool aDidResetScrollPositionForLayerPixelAlignment); + + /** + * Attempt to prepare an ImageLayer based upon the provided PaintedLayerData. + * Returns nullptr on failure. + */ + already_AddRefed<Layer> PrepareImageLayer(PaintedLayerData* aData); + + /** + * Attempt to prepare a ColorLayer based upon the provided PaintedLayerData. + * Returns nullptr on failure. + */ + already_AddRefed<Layer> PrepareColorLayer(PaintedLayerData* aData); + /** * Grab the next recyclable ColorLayer, or create one if there are no * more recyclable ColorLayers. */ already_AddRefed<ColorLayer> CreateOrRecycleColorLayer(PaintedLayer* aPainted); /** * Grab the next recyclable ImageLayer, or create one if there are no * more recyclable ImageLayers. @@ -2347,18 +2366,28 @@ PaintedLayerData::UpdateCommonClipCount( if (mCommonClipCount >= 0) { mCommonClipCount = mItemClip.GetCommonRoundedRectCount(aCurrentClip, mCommonClipCount); } else { // first item in the layer mCommonClipCount = aCurrentClip.GetRoundedRectCount(); } } +bool +PaintedLayerData::CanOptimizeToImageLayer(nsDisplayListBuilder* aBuilder) +{ + if (!mImage) { + return nullptr; + } + + return mImage->CanOptimizeToImageLayer(mLayer->Manager(), aBuilder); +} + already_AddRefed<ImageContainer> -PaintedLayerData::CanOptimizeImageLayer(nsDisplayListBuilder* aBuilder) +PaintedLayerData::GetContainerForImageLayer(nsDisplayListBuilder* aBuilder) { if (!mImage) { return nullptr; } return mImage->GetContainer(mLayer->Manager(), aBuilder); } @@ -2781,16 +2810,68 @@ static int32_t FindIndexOfLayerIn(nsTArr if (aArray[i].mLayer == aLayer) { return i; } } return -1; } #endif +already_AddRefed<Layer> +ContainerState::PrepareImageLayer(PaintedLayerData* aData) +{ + nsRefPtr<ImageContainer> imageContainer = + aData->GetContainerForImageLayer(mBuilder); + if (!imageContainer) { + return nullptr; + } + + nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(aData->mLayer); + imageLayer->SetContainer(imageContainer); + aData->mImage->ConfigureLayer(imageLayer, mParameters); + imageLayer->SetPostScale(mParameters.mXScale, + mParameters.mYScale); + + if (aData->mItemClip.HasClip()) { + ParentLayerIntRect clip = + ViewAs<ParentLayerPixel>(ScaleToNearestPixels(aData->mItemClip.GetClipRect())); + clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset)); + imageLayer->SetClipRect(Some(clip)); + } else { + imageLayer->SetClipRect(Nothing()); + } + + mLayerBuilder->StoreOptimizedLayerForFrame(aData->mImage, imageLayer); + FLB_LOG_PAINTED_LAYER_DECISION(aData, + " Selected image layer=%p\n", imageLayer.get()); + + return imageLayer.forget(); +} + +already_AddRefed<Layer> +ContainerState::PrepareColorLayer(PaintedLayerData* aData) +{ + nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(aData->mLayer); + colorLayer->SetColor(aData->mSolidColor); + + // Copy transform + colorLayer->SetBaseTransform(aData->mLayer->GetBaseTransform()); + colorLayer->SetPostScale(aData->mLayer->GetPostXScale(), + aData->mLayer->GetPostYScale()); + + nsIntRect visibleRect = aData->mVisibleRegion.GetBounds(); + visibleRect.MoveBy(-GetTranslationForPaintedLayer(aData->mLayer)); + colorLayer->SetBounds(visibleRect); + colorLayer->SetClipRect(Nothing()); + + FLB_LOG_PAINTED_LAYER_DECISION(aData, + " Selected color layer=%p\n", colorLayer.get()); + + return colorLayer.forget(); +} template<typename FindOpaqueBackgroundColorCallbackType> void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueBackgroundColorCallbackType aFindOpaqueBackgroundColor) { PaintedLayerData* data = &aData; if (!data->mLayer) { // No layer was recycled, so we create a new one. @@ -2809,82 +2890,56 @@ void ContainerState::FinishPaintedLayerD mLayerBuilder->AddPaintedDisplayItem(data, item.mItem, item.mClip, *this, item.mLayerState, data->mAnimatedGeometryRootOffset); } NewLayerEntry* newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex]; nsRefPtr<Layer> layer; - nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer(mBuilder); + bool canOptimizeToImageLayer = data->CanOptimizeToImageLayer(mBuilder); FLB_LOG_PAINTED_LAYER_DECISION(data, "Selecting layer for pld=%p\n", data); - FLB_LOG_PAINTED_LAYER_DECISION(data, " Solid=%i, hasImage=%i, canOptimizeAwayPaintedLayer=%i\n", - data->mIsSolidColorInVisibleRegion, !!imageContainer, + FLB_LOG_PAINTED_LAYER_DECISION(data, " Solid=%i, hasImage=%c, canOptimizeAwayPaintedLayer=%i\n", + data->mIsSolidColorInVisibleRegion, canOptimizeToImageLayer ? 'y' : 'n', CanOptimizeAwayPaintedLayer(data, mLayerBuilder)); - if ((data->mIsSolidColorInVisibleRegion || imageContainer) && + if ((data->mIsSolidColorInVisibleRegion || canOptimizeToImageLayer) && CanOptimizeAwayPaintedLayer(data, mLayerBuilder)) { - NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer), + NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && canOptimizeToImageLayer), "Can't be a solid color as well as an image!"); - if (imageContainer) { - nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer); - imageLayer->SetContainer(imageContainer); - data->mImage->ConfigureLayer(imageLayer, mParameters); - imageLayer->SetPostScale(mParameters.mXScale, - mParameters.mYScale); - if (data->mItemClip.HasClip()) { - ParentLayerIntRect clip = ViewAs<ParentLayerPixel>(ScaleToNearestPixels(data->mItemClip.GetClipRect())); - clip.MoveBy(ViewAs<ParentLayerPixel>(mParameters.mOffset)); - imageLayer->SetClipRect(Some(clip)); - } else { - imageLayer->SetClipRect(Nothing()); - } - layer = imageLayer; - mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage, - imageLayer); - FLB_LOG_PAINTED_LAYER_DECISION(data, " Selected image layer=%p\n", layer.get()); - } else { - nsRefPtr<ColorLayer> colorLayer = CreateOrRecycleColorLayer(data->mLayer); - colorLayer->SetColor(data->mSolidColor); - - // Copy transform - colorLayer->SetBaseTransform(data->mLayer->GetBaseTransform()); - colorLayer->SetPostScale(data->mLayer->GetPostXScale(), data->mLayer->GetPostYScale()); - - nsIntRect visibleRect = data->mVisibleRegion.GetBounds(); - visibleRect.MoveBy(-GetTranslationForPaintedLayer(data->mLayer)); - colorLayer->SetBounds(visibleRect); - colorLayer->SetClipRect(Nothing()); - - layer = colorLayer; - FLB_LOG_PAINTED_LAYER_DECISION(data, " Selected color layer=%p\n", layer.get()); + + layer = canOptimizeToImageLayer ? PrepareImageLayer(data) + : PrepareColorLayer(data); + + if (layer) { + NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, + "Layer already in list???"); + NS_ASSERTION(newLayerEntry->mLayer == data->mLayer, + "Painted layer at wrong index"); + // Store optimized layer in reserved slot + newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1]; + NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?"); + newLayerEntry->mLayer = layer; + newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot; + newLayerEntry->mFixedPosFrameForLayerData = data->mFixedPosFrameForLayerData; + + // Hide the PaintedLayer. We leave it in the layer tree so that we + // can find and recycle it later. + ParentLayerIntRect emptyRect; + data->mLayer->SetClipRect(Some(emptyRect)); + data->mLayer->SetVisibleRegion(nsIntRegion()); + data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion().GetBounds()); + data->mLayer->SetEventRegions(EventRegions()); } - - NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, - "Layer already in list???"); - NS_ASSERTION(newLayerEntry->mLayer == data->mLayer, - "Painted layer at wrong index"); - // Store optimized layer in reserved slot - newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex + 1]; - NS_ASSERTION(!newLayerEntry->mLayer, "Slot already occupied?"); - newLayerEntry->mLayer = layer; - newLayerEntry->mAnimatedGeometryRoot = data->mAnimatedGeometryRoot; - newLayerEntry->mFixedPosFrameForLayerData = data->mFixedPosFrameForLayerData; - - // Hide the PaintedLayer. We leave it in the layer tree so that we - // can find and recycle it later. - ParentLayerIntRect emptyRect; - data->mLayer->SetClipRect(Some(emptyRect)); - data->mLayer->SetVisibleRegion(nsIntRegion()); - data->mLayer->InvalidateRegion(data->mLayer->GetValidRegion().GetBounds()); - data->mLayer->SetEventRegions(EventRegions()); - } else { + } + + if (!layer) { + // We couldn't optimize to an image layer or a color layer above. layer = data->mLayer; - imageContainer = nullptr; layer->SetClipRect(Nothing()); FLB_LOG_PAINTED_LAYER_DECISION(data, " Selected painted layer=%p\n", layer.get()); } if (mLayerBuilder->IsBuildingRetainedLayers()) { newLayerEntry->mVisibleRegion = data->mVisibleRegion; newLayerEntry->mOpaqueRegion = data->mOpaqueRegion; newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow;
--- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -5188,24 +5188,40 @@ nsImageRenderer::IsAnimatedImage() return false; bool animated = false; if (NS_SUCCEEDED(mImageContainer->GetAnimated(&animated)) && animated) return true; return false; } -already_AddRefed<mozilla::layers::ImageContainer> -nsImageRenderer::GetContainer(LayerManager* aManager) +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() { if (mType != eStyleImageType_Image || !mImageContainer) { return nullptr; } - return mImageContainer->GetImageContainer(aManager, imgIContainer::FLAG_NONE); + nsCOMPtr<imgIContainer> image = mImageContainer; + return image.forget(); } #define MAX_BLUR_RADIUS 300 #define MAX_SPREAD_RADIUS 50 static inline gfxPoint ComputeBlurStdDev(nscoord aBlurRadius, int32_t aAppUnitsPerDevPixel, gfxFloat aScaleX,
--- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -232,17 +232,29 @@ public: const mozilla::CSSIntRect& aSrc, uint8_t aHFill, uint8_t aVFill, const nsSize& aUnitSize, uint8_t aIndex); bool IsRasterImage(); bool IsAnimatedImage(); - already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager); + + /** + * @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(); bool IsReady() { return mIsReady; } private: /** * Draws the image to the target rendering context. * aSrc is a rect on the source image which will be mapped to aDest; it's * currently only used for gradients.
--- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2291,21 +2291,22 @@ nsDisplayBackgroundImage::ShouldFixToVie // Put background-attachment:fixed background images in their own // compositing layer, unless we have APZ enabled return mBackgroundStyle->mLayers[mLayer].mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED && !mBackgroundStyle->mLayers[mLayer].mImage.IsEmpty(); } bool -nsDisplayBackgroundImage::TryOptimizeToImageLayer(LayerManager* aManager, +nsDisplayBackgroundImage::CanOptimizeToImageLayer(LayerManager* aManager, nsDisplayListBuilder* aBuilder) { - if (!mBackgroundStyle) + if (!mBackgroundStyle) { return false; + } nsPresContext* presContext = mFrame->PresContext(); uint32_t flags = aBuilder->GetBackgroundPaintFlags(); nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer]; if (layer.mClip != NS_STYLE_BG_CLIP_BORDER) { return false; @@ -2315,51 +2316,65 @@ nsDisplayBackgroundImage::TryOptimizeToI return false; } nsBackgroundLayerState state = nsCSSRendering::PrepareBackgroundLayer(presContext, mFrame, flags, borderArea, borderArea, layer); nsImageRenderer* imageRenderer = &state.mImageRenderer; // We only care about images here, not gradients. - if (!imageRenderer->IsRasterImage()) + if (!imageRenderer->IsRasterImage()) { return false; - - nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer(aManager); - // Image is not ready to be made into a layer yet - if (!imageContainer) + } + + 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 or partial backgrounds. if (!state.mDestArea.IsEqualEdges(state.mFillArea)) { return false; } // XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to // layer pixel boundaries. This should be OK for now. int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); mDestRect = LayoutDeviceRect::FromAppUnits(state.mDestArea, appUnitsPerDevPixel); - mImageContainer = imageContainer; // Ok, we can turn this into a layer if needed. + mImage = imageRenderer->GetImage(); + MOZ_ASSERT(mImage); + return true; } already_AddRefed<ImageContainer> nsDisplayBackgroundImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder *aBuilder) { - if (!TryOptimizeToImageLayer(aManager, aBuilder)) { + if (!mImage) { + MOZ_ASSERT_UNREACHABLE("Must call CanOptimizeToImage() and get true " + "before calling GetContainer()"); return nullptr; } + if (!mImageContainer) { + // We don't have an ImageContainer yet; get it from mImage. + + uint32_t flags = aBuilder->ShouldSyncDecodeImages() + ? imgIContainer::FLAG_SYNC_DECODE + : imgIContainer::FLAG_NONE; + + mImageContainer = mImage->GetImageContainer(aManager, flags); + } + nsRefPtr<ImageContainer> container = mImageContainer; - return container.forget(); } LayerState nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aParameters) { @@ -2381,29 +2396,34 @@ nsDisplayBackgroundImage::GetLayerState( if (!animated || !nsLayoutUtils::AnimatedImageLayersEnabled()) { if (!aManager->IsCompositingCheap() || !nsLayoutUtils::GPUImageScalingEnabled()) { return LAYER_NONE; } } - if (!TryOptimizeToImageLayer(aManager, aBuilder)) { + if (!CanOptimizeToImageLayer(aManager, aBuilder)) { return LAYER_NONE; } + MOZ_ASSERT(mImage); + if (!animated) { - mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize(); - NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!"); + int32_t imageWidth; + int32_t imageHeight; + mImage->GetWidth(&imageWidth); + mImage->GetHeight(&imageHeight); + NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!"); const LayerRect destLayerRect = mDestRect * aParameters.Scale(); // Calculate the scaling factor for the frame. - const gfxSize scale = gfxSize(destLayerRect.width / imageSize.width, - destLayerRect.height / imageSize.height); + const gfxSize scale = gfxSize(destLayerRect.width / imageWidth, + destLayerRect.height / imageHeight); // If we are not scaling at all, no point in separating this into a layer. if (scale.width == 1.0f && scale.height == 1.0f) { return LAYER_NONE; } // If the target size is pretty small, no point in using a layer. if (destLayerRect.width * destLayerRect.height < 64 * 64) { @@ -2421,45 +2441,51 @@ nsDisplayBackgroundImage::BuildLayer(nsD { nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*> (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this)); if (!layer) { layer = aManager->CreateImageLayer(); if (!layer) return nullptr; } - layer->SetContainer(mImageContainer); + nsRefPtr<ImageContainer> imageContainer = GetContainer(aManager, aBuilder); + layer->SetContainer(imageContainer); ConfigureLayer(layer, aParameters); return layer.forget(); } void nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer, const ContainerLayerParameters& aParameters) { aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame)); - mozilla::gfx::IntSize imageSize = mImageContainer->GetCurrentSize(); - NS_ASSERTION(imageSize.width != 0 && imageSize.height != 0, "Invalid image size!"); - if (imageSize.width > 0 && imageSize.height > 0) { + MOZ_ASSERT(mImage); + int32_t imageWidth; + int32_t imageHeight; + mImage->GetWidth(&imageWidth); + mImage->GetHeight(&imageHeight); + NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!"); + + if (imageWidth > 0 && imageHeight > 0) { // We're actually using the ImageContainer. Let our frame know that it // should consider itself to have painted successfully. nsDisplayBackgroundGeometry::UpdateDrawResult(this, DrawResult::SUCCESS); } // XXX(seth): Right now we ignore aParameters.Scale() and // aParameters.Offset(), because FrameLayerBuilder already applies // aParameters.Scale() via the layer's post-transform, and // aParameters.Offset() is always zero. MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0)); const LayoutDevicePoint p = mDestRect.TopLeft(); Matrix transform = Matrix::Translation(p.x, p.y); - transform.PreScale(mDestRect.width / imageSize.width, - mDestRect.height / imageSize.height); + transform.PreScale(mDestRect.width / imageWidth, + mDestRect.height / imageHeight); aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); } void nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
--- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1983,16 +1983,24 @@ public: typedef mozilla::LayoutDeviceRect LayoutDeviceRect; typedef mozilla::layers::ImageContainer ImageContainer; typedef mozilla::layers::ImageLayer ImageLayer; nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : nsDisplayItem(aBuilder, aFrame) {} + /** + * @return true if this display item can be optimized into an image layer. + * It is an error to call GetContainer() unless you've called + * CanOptimizeToImageLayer() first and it returned true. + */ + virtual bool CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) = 0; + virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder) = 0; virtual void ConfigureLayer(ImageLayer* aLayer, const ContainerLayerParameters& aParameters) = 0; virtual bool SupportsOptimizingToImage() override { return true; } }; @@ -2331,16 +2339,18 @@ public: { return new nsDisplayBackgroundGeometry(this, aBuilder); } virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, nsRegion* aInvalidRegion) override; + virtual bool CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) override; virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager, nsDisplayListBuilder *aBuilder) override; virtual void ConfigureLayer(ImageLayer* aLayer, const ContainerLayerParameters& aParameters) override; static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, nsPresContext* aPresContext, uint8_t aClip, const nsRect& aRect, bool* aSnap); @@ -2357,17 +2367,17 @@ protected: nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder); void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, const nsRect& aBounds, nsRect* aClipRect); // Cache the result of nsCSSRendering::FindBackground. Always null if // mIsThemed is true or if FindBackground returned false. const nsStyleBackground* mBackgroundStyle; - /* If this background can be a simple image layer, we store the format here. */ + nsCOMPtr<imgIContainer> mImage; nsRefPtr<ImageContainer> mImageContainer; LayoutDeviceRect mDestRect; /* Bounds of this display item */ nsRect mBounds; uint32_t mLayer; };
--- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1410,16 +1410,27 @@ nsDisplayImage::ComputeInvalidationRegio geometry->ShouldInvalidateToSyncDecodeImages()) { bool snap; aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap)); } nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); } +bool +nsDisplayImage::CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) +{ + uint32_t flags = aBuilder->ShouldSyncDecodeImages() + ? imgIContainer::FLAG_SYNC_DECODE + : imgIContainer::FLAG_NONE; + + return mImage->IsImageContainerAvailable(aManager, flags); +} + already_AddRefed<ImageContainer> nsDisplayImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder) { uint32_t flags = aBuilder->ShouldSyncDecodeImages() ? imgIContainer::FLAG_SYNC_DECODE : imgIContainer::FLAG_NONE; @@ -1498,19 +1509,17 @@ nsDisplayImage::GetLayerState(nsDisplayL return LAYER_NONE; } } uint32_t flags = aBuilder->ShouldSyncDecodeImages() ? imgIContainer::FLAG_SYNC_DECODE : imgIContainer::FLAG_NONE; - nsRefPtr<ImageContainer> container = - mImage->GetImageContainer(aManager, flags); - if (!container) { + if (!mImage->IsImageContainerAvailable(aManager, flags)) { return LAYER_NONE; } return LAYER_ACTIVE; } /* virtual */ nsRegion
--- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -389,16 +389,19 @@ public: virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override; virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, nsRegion* aInvalidRegion) override; virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override; + virtual bool CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) override; + /** * Returns an ImageContainer for this image if the image type * supports it (TYPE_RASTER only). */ virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder) override; /**
--- a/layout/xul/nsImageBoxFrame.cpp +++ b/layout/xul/nsImageBoxFrame.cpp @@ -432,41 +432,77 @@ nsDisplayXULImage::ConfigureLayer(ImageL const LayoutDevicePoint p = destRect.TopLeft(); Matrix transform = Matrix::Translation(p.x, p.y); transform.PreScale(destRect.Width() / imageWidth, destRect.Height() / imageHeight); aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); } +bool +nsDisplayXULImage::CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) +{ + uint32_t flags = aBuilder->ShouldSyncDecodeImages() + ? imgIContainer::FLAG_SYNC_DECODE + : imgIContainer::FLAG_NONE; + + return static_cast<nsImageBoxFrame*>(mFrame) + ->IsImageContainerAvailable(aManager, flags); +} + +bool +nsImageBoxFrame::IsImageContainerAvailable(LayerManager* aManager, + uint32_t aFlags) +{ + bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0); + if (hasSubRect || !mImageRequest) { + return false; + } + + nsCOMPtr<imgIContainer> imgCon; + mImageRequest->GetImage(getter_AddRefs(imgCon)); + if (!imgCon) { + return false; + } + + return imgCon->IsImageContainerAvailable(aManager, aFlags); +} + already_AddRefed<ImageContainer> nsDisplayXULImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder) { uint32_t flags = aBuilder->ShouldSyncDecodeImages() ? 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) { - bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0); - if (hasSubRect || !mImageRequest) { + 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> 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); } // // DidSetStyleContext // // When the style context changes, make sure that all of our image is up to date.
--- a/layout/xul/nsImageBoxFrame.h +++ b/layout/xul/nsImageBoxFrame.h @@ -91,16 +91,17 @@ public: const nsDisplayListSet& aLists) override; virtual ~nsImageBoxFrame(); DrawResult PaintImage(nsRenderingContext& aRenderingContext, const nsRect& aDirtyRect, nsPoint aPt, uint32_t aFlags); + bool IsImageContainerAvailable(LayerManager* aManager, uint32_t aFlags); already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager, uint32_t aFlags); protected: explicit nsImageBoxFrame(nsStyleContext* aContext); virtual void GetImageSize(); @@ -137,16 +138,18 @@ public: MOZ_COUNT_CTOR(nsDisplayXULImage); } #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayXULImage() { MOZ_COUNT_DTOR(nsDisplayXULImage); } #endif + virtual bool CanOptimizeToImageLayer(LayerManager* aManager, + nsDisplayListBuilder* aBuilder) override; virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder) override; virtual void ConfigureLayer(ImageLayer* aLayer, const ContainerLayerParameters& aParameters) override; virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override { *aSnap = true; return nsRect(ToReferenceFrame(), Frame()->GetSize());