From f6dd40d9e0b856d6687081138ce505da732b1912 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Thu, 17 Jul 2014 11:24:47 -0400 Subject: [PATCH] Backed out 46 changesets (bug 1022612) for B2G mochitest permafails on a CLOSED TREE. Backed out changeset 34b3014a3112 (bug 1022612) Backed out changeset 6ae9316fd909 (bug 1022612) Backed out changeset b8f3749c95eb (bug 1022612) Backed out changeset caab10bf6ca3 (bug 1022612) Backed out changeset 0c57c620c898 (bug 1022612) Backed out changeset fac64141a00a (bug 1022612) Backed out changeset bf0df1c9d68b (bug 1022612) Backed out changeset b42054800020 (bug 1022612) Backed out changeset 667793b21194 (bug 1022612) Backed out changeset f14ada64fe1b (bug 1022612) Backed out changeset 75b837686bdf (bug 1022612) Backed out changeset 66de53183a22 (bug 1022612) Backed out changeset 0ff86ced4d46 (bug 1022612) Backed out changeset 18eecc5b1ef7 (bug 1022612) Backed out changeset 2763c4878de5 (bug 1022612) Backed out changeset b72413ecc385 (bug 1022612) Backed out changeset b23f1081afb8 (bug 1022612) Backed out changeset f7e2c6a72043 (bug 1022612) Backed out changeset 959917c9027d (bug 1022612) Backed out changeset 0268a46f4880 (bug 1022612) Backed out changeset 3388856a80ad (bug 1022612) Backed out changeset e4b17cf0f806 (bug 1022612) Backed out changeset 2f4e9da0e4b6 (bug 1022612) Backed out changeset 489f6a7c0c03 (bug 1022612) Backed out changeset 8369d9ad7ad3 (bug 1022612) Backed out changeset 0758d2a06002 (bug 1022612) Backed out changeset f2ae9cb22edb (bug 1022612) Backed out changeset 9c48c6ee5dc2 (bug 1022612) Backed out changeset fe7134400f08 (bug 1022612) Backed out changeset cc2c5397ca8b (bug 1022612) Backed out changeset a3d1a3e8b39d (bug 1022612) Backed out changeset 8974b74b0eb0 (bug 1022612) Backed out changeset 75f7dbb5a2a6 (bug 1022612) Backed out changeset 2aa04a071e60 (bug 1022612) Backed out changeset f2ab1bcd4c39 (bug 1022612) Backed out changeset da9152b6ea29 (bug 1022612) Backed out changeset 58abf5b0e148 (bug 1022612) Backed out changeset 797058a09ad2 (bug 1022612) Backed out changeset ea3e99a92ff0 (bug 1022612) Backed out changeset adc4a4a7aa73 (bug 1022612) Backed out changeset 7b18dedd1505 (bug 1022612) Backed out changeset 055dd1921e8e (bug 1022612) Backed out changeset 42fa2c97e989 (bug 1022612) Backed out changeset cd594236388f (bug 1022612) Backed out changeset 9eadc5fee43d (bug 1022612) Backed out changeset 5cc8d30ff7c9 (bug 1022612) --- layout/base/FrameLayerBuilder.cpp | 747 +++++------------- layout/base/FrameLayerBuilder.h | 60 +- layout/base/nsDisplayList.cpp | 472 +++++++---- layout/base/nsDisplayList.h | 382 +++++---- layout/base/nsLayoutDebugger.cpp | 5 +- layout/base/nsLayoutUtils.cpp | 17 +- layout/base/nsLayoutUtils.h | 8 - layout/base/nsPresShell.cpp | 1 + layout/forms/nsSelectsAreaFrame.cpp | 3 - layout/generic/nsCanvasFrame.h | 3 +- layout/generic/nsFrame.cpp | 70 +- layout/generic/nsHTMLCanvasFrame.cpp | 1 + layout/generic/nsIFrame.h | 9 - layout/generic/nsImageFrame.cpp | 1 + layout/generic/nsObjectFrame.cpp | 47 +- layout/generic/nsObjectFrame.h | 3 +- layout/generic/nsPageFrame.cpp | 36 +- layout/generic/nsSimplePageSequenceFrame.cpp | 14 +- layout/generic/nsSubDocumentFrame.cpp | 7 + layout/generic/nsVideoFrame.cpp | 1 + layout/ipc/RenderFrameParent.cpp | 2 + layout/reftests/bugs/1022612-1-ref.html | 7 - layout/reftests/bugs/1022612-1.html | 7 - layout/reftests/bugs/reftest.list | 3 +- .../fieldset/positioned-container-1-ref.html | 2 +- .../fieldset/positioned-container-1.html | 2 +- layout/reftests/text/reftest.list | 2 +- layout/tables/nsTableFrame.cpp | 14 + layout/tables/nsTableFrame.h | 2 + layout/xul/nsBoxFrame.cpp | 7 +- layout/xul/nsImageBoxFrame.cpp | 2 + testing/testsuite-targets.mk | 4 +- 32 files changed, 852 insertions(+), 1089 deletions(-) delete mode 100644 layout/reftests/bugs/1022612-1-ref.html delete mode 100644 layout/reftests/bugs/1022612-1.html diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index ac71cd67408..d9673a4c537 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -23,7 +23,6 @@ #include "ImageContainer.h" #include "ActiveLayerTracker.h" #include "gfx2DGlue.h" -#include "mozilla/LookAndFeel.h" #include "GeckoProfiler.h" #include "mozilla/gfx/Tools.h" @@ -37,6 +36,8 @@ using namespace mozilla::gfx; namespace mozilla { +class ContainerState; + FrameLayerBuilder::DisplayItemData::DisplayItemData(LayerManagerData* aParent, uint32_t aKey, Layer* aLayer, LayerState aLayerState, uint32_t aGeneration) @@ -242,10 +243,8 @@ public: mSingleItemFixedToViewport(false), mNeedComponentAlpha(false), mForceTransparentSurface(false), - mHideAllLayersBelow(false), mImage(nullptr), mCommonClipCount(-1), - mNewChildLayersIndex(-1), mAllDrawingAbove(false) {} /** @@ -263,7 +262,6 @@ public: */ void Accumulate(ContainerState* aState, nsDisplayItem* aItem, - const nsIntRegion& aClippedOpaqueRegion, const nsIntRect& aVisibleRect, const nsIntRect& aDrawRect, const DisplayItemClip& aClip); @@ -293,7 +291,7 @@ public: { if (!mAllDrawingAbove) { mDrawAboveRegion.Or(mDrawAboveRegion, aAbove); - mDrawAboveRegion.SimplifyOutward(8); + mDrawAboveRegion.SimplifyOutward(4); } } @@ -301,7 +299,7 @@ public: { if (!mAllDrawingAbove) { mVisibleAboveRegion.Or(mVisibleAboveRegion, aAbove); - mVisibleAboveRegion.SimplifyOutward(8); + mVisibleAboveRegion.SimplifyOutward(4); } } @@ -312,11 +310,11 @@ public: } else { mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleAboveRegion); mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleRegion); - mVisibleAboveRegion.SimplifyOutward(8); + mVisibleAboveRegion.SimplifyOutward(4); mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawAboveRegion); mDrawAboveRegion.Or(mDrawAboveRegion, aOther->mDrawRegion); - mDrawAboveRegion.SimplifyOutward(8); - } + mDrawAboveRegion.SimplifyOutward(4); + } } void SetAllDrawingAbove() @@ -424,10 +422,6 @@ public: * part of its surface. */ bool mForceTransparentSurface; - /** - * Set if all layers below this ThebesLayer should be hidden. - */ - bool mHideAllLayersBelow; /** * Stores the pointer to the nsDisplayImage if we want to @@ -450,10 +444,6 @@ public: * data is popped from the stack. */ int32_t mCommonClipCount; - /** - * Index of this layer in mNewChildLayers. - */ - int32_t mNewChildLayersIndex; /* * Updates mCommonClipCount by checking for rounded rect clips in common * between the clip on a new item (aCurrentClip) and the common clips @@ -487,39 +477,6 @@ private: bool mAllDrawingAbove; }; -struct NewLayerEntry { - NewLayerEntry() - : mAnimatedGeometryRoot(nullptr) - , mFixedPosFrameForLayerData(nullptr) - , mLayerContentsVisibleRect(0, 0, -1, -1) - , mHideAllLayersBelow(false) - , mOpaqueForAnimatedGeometryRootParent(false) - {} - // mLayer is null if the previous entry is for a ThebesLayer that hasn't - // been optimized to some other form (yet). - nsRefPtr mLayer; - const nsIFrame* mAnimatedGeometryRoot; - const nsIFrame* mFixedPosFrameForLayerData; - // The following are only used for retained layers (for occlusion - // culling of those layers). These regions are all relative to the - // container reference frame. - nsIntRegion mVisibleRegion; - nsIntRegion mOpaqueRegion; - // This rect is in the layer's own coordinate space. The computed visible - // region for the layer cannot extend beyond this rect. - nsIntRect mLayerContentsVisibleRect; - bool mHideAllLayersBelow; - // When mOpaqueForAnimatedGeometryRootParent is true, the opaque region of - // this layer is opaque in the same position even subject to the animation of - // geometry of mAnimatedGeometryRoot. For example when mAnimatedGeometryRoot - // is a scrolled frame and the scrolled content is opaque everywhere in the - // displayport, we can set this flag. - // When this flag is set, we can treat this opaque region as covering - // content whose animated geometry root is the animated geometry root for - // mAnimatedGeometryRoot->GetParent(). - bool mOpaqueForAnimatedGeometryRootParent; -}; - /** * This is a helper object used to build up the layer children for * a ContainerLayer. @@ -531,14 +488,12 @@ public: FrameLayerBuilder* aLayerBuilder, nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem, - const nsRect& aContainerBounds, ContainerLayer* aContainerLayer, const ContainerLayerParameters& aParameters) : mBuilder(aBuilder), mManager(aManager), mLayerBuilder(aLayerBuilder), mContainerFrame(aContainerFrame), mContainerLayer(aContainerLayer), - mContainerBounds(aContainerBounds), mParameters(aParameters), mNextFreeRecycledThebesLayer(0) { @@ -550,10 +505,6 @@ public: mContainerAnimatedGeometryRoot = aContainerItem ? nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder) : mContainerReferenceFrame; - NS_ASSERTION(!aContainerItem || !aContainerItem->ShouldFixToViewport(aBuilder), - "Container items never return true for ShouldFixToViewport"); - mContainerFixedPosFrame = - FindFixedPosFrameForLayerData(mContainerAnimatedGeometryRoot, false); // When AllowResidualTranslation is false, display items will be drawn // scaled with a translation by integer pixels, so we know how the snapping // will work. @@ -570,7 +521,7 @@ public: * This is the method that actually walks a display list and builds * the child layers. */ - void ProcessDisplayItems(nsDisplayList* aList, uint32_t aFlags); + void ProcessDisplayItems(const nsDisplayList& aList, uint32_t aFlags); /** * This finalizes all the open ThebesLayers by popping every element off * mThebesLayerDataStack, then sets the children of the container layer @@ -579,9 +530,9 @@ public: * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA, * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA */ - void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData, - const nsIntRect& aContainerPixelBounds, - nsDisplayList* aChildItems); + void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData); + + nsRect GetChildrenBounds() { return mBounds; } nscoord GetAppUnitsPerDevPixel() { return mAppUnitsPerDevPixel; } @@ -630,18 +581,6 @@ public: mAppUnitsPerDevPixel); } - nsIFrame* GetContainerFrame() const { return mContainerFrame; } - - /** - * Sets aOuterVisibleRegion as aLayer's visible region. aOuterVisibleRegion - * is in the coordinate space of the container reference frame. - * aLayerContentsVisibleRect, if non-null, is in the layer's own - * coordinate system. - */ - void SetOuterVisibleRegionForLayer(Layer* aLayer, - const nsIntRegion& aOuterVisibleRegion, - const nsIntRect* aLayerContentsVisibleRect = nullptr) const; - protected: friend class ThebesLayerData; @@ -714,36 +653,6 @@ protected: */ void SetFixedPositionLayerData(Layer* aLayer, const nsIFrame* aFixedPosFrame); - - /** - * Returns true if aItem's opaque area (in aOpaque) covers the entire - * scrollable area of its presshell. - */ - bool ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque); - - /** - * For each layer in mNewChildLayers, remove from its visible region the - * opaque regions of the layers at higher z-index, but only if they have - * the same animated geometry root and fixed-pos frame ancestor. - * The opaque region for the child layers that share the same animated - * geometry root as the container frame is returned in - * *aOpaqueRegionForContainer. - */ - void ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer); - - /** - * Computes the snapped opaque area of aItem. Sets aList's opaque flag - * if it covers the entire list bounds. Sets *aHideAllLayersBelow to true - * this item covers the entire viewport so that all layers below are - * permanently invisible. - */ - nsIntRegion ComputeOpaqueRect(nsDisplayItem* aItem, - const nsIFrame* aAnimatedGeometryRoot, - const nsIFrame* aFixedPosFrame, - const DisplayItemClip& aClip, - nsDisplayList* aList, - bool* aHideAllLayersBelow); - /** * Indicate that we are done adding items to the ThebesLayer at the top of * mThebesLayerDataStack. Set the final visible region and opaque-content @@ -786,14 +695,11 @@ protected: * Builds an ImageLayer for the appropriate backend; the mask is relative to * aLayer's visible region. * aLayer is the layer to be clipped. - * aLayerVisibleRegion is the region that will be set as aLayer's visible region, - * relative to the container reference frame * aRoundedRectClipCount is used when building mask layers for ThebesLayers, * SetupMaskLayer will build a mask layer for only the first * aRoundedRectClipCount rounded rects in aClip */ void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip, - const nsIntRegion& aLayerVisibleRegion, uint32_t aRoundedRectClipCount = UINT32_MAX); bool ChooseAnimatedGeometryRoot(const nsDisplayList& aList, @@ -805,27 +711,21 @@ protected: nsIFrame* mContainerFrame; nsIFrame* mContainerReferenceFrame; const nsIFrame* mContainerAnimatedGeometryRoot; - const nsIFrame* mContainerFixedPosFrame; ContainerLayer* mContainerLayer; - nsRect mContainerBounds; - DebugOnly mAccumulatedChildBounds; ContainerLayerParameters mParameters; /** * The region of ThebesLayers that should be invalidated every time * we recycle one. */ nsIntRegion mInvalidThebesContent; + nsRect mBounds; nsAutoTArray,1> mThebesLayerDataStack; /** * We collect the list of children in here. During ProcessDisplayItems, * the layers in this array either have mContainerLayer as their parent, * or no parent. - * ThebesLayers have two entries in this array: the second one is used only if - * the ThebesLayer is optimized away to a ColorLayer or ImageLayer. - * It's essential that this array is only appended to, since ThebesLayerData - * records the index of its ThebesLayer in this array. */ - typedef nsAutoTArray AutoLayersArray; + typedef nsAutoTArray,1> AutoLayersArray; AutoLayersArray mNewChildLayers; nsTArray > mRecycledThebesLayers; nsDataHashtable, nsRefPtr > @@ -1701,62 +1601,41 @@ AppUnitsPerDevPixel(nsDisplayItem* aItem) #endif /** - * Set the visible region for aLayer. - * aOuterVisibleRegion is the visible region relative to the parent layer. - * aLayerContentsVisibleRect, if non-null, is a rectangle in the layer's - * own coordinate system to which the layer's visible region is restricted. - * Consumes *aOuterVisibleRegion. + * Restrict the visible region of aLayer to the region that is actually visible. + * Because we only reduce the visible region here, we don't need to worry + * about whether CONTENT_OPAQUE is set; if layer was opaque in the old + * visible region, it will still be opaque in the new one. + * @param aLayerVisibleRegion the visible region of the layer, in the layer's + * coordinate space + * @param aRestrictToRect the rect to restrict the visible region to, in the + * parent's coordinate system */ static void -SetOuterVisibleRegion(Layer* aLayer, nsIntRegion* aOuterVisibleRegion, - const nsIntRect* aLayerContentsVisibleRect = nullptr) +SetVisibleRegionForLayer(Layer* aLayer, const nsIntRegion& aLayerVisibleRegion, + const nsIntRect& aRestrictToRect) { gfx3DMatrix transform; To3DMatrix(aLayer->GetTransform(), transform); - gfxMatrix transform2D; - if (transform.Is2D(&transform2D) && !transform2D.HasNonIntegerTranslation()) { - aOuterVisibleRegion->MoveBy(-int(transform2D._31), -int(transform2D._32)); - if (aLayerContentsVisibleRect) { - aOuterVisibleRegion->And(*aOuterVisibleRegion, *aLayerContentsVisibleRect); - } + + // if 'transform' is not invertible, then nothing will be displayed + // for the layer, so it doesn't really matter what we do here + gfxRect itemVisible(aRestrictToRect.x, aRestrictToRect.y, + aRestrictToRect.width, aRestrictToRect.height); + nsIntRect childBounds = aLayerVisibleRegion.GetBounds(); + gfxRect childGfxBounds(childBounds.x, childBounds.y, + childBounds.width, childBounds.height); + gfxRect layerVisible = transform.Inverse().ProjectRectBounds(itemVisible); + layerVisible = layerVisible.Intersect(childGfxBounds); + layerVisible.RoundOut(); + + nsIntRect visibleRect; + if (!gfxUtils::GfxRectToIntRect(layerVisible, &visibleRect)) { + aLayer->SetVisibleRegion(nsIntRegion()); } else { - nsIntRect outerRect = aOuterVisibleRegion->GetBounds(); - // if 'transform' is not invertible, then nothing will be displayed - // for the layer, so it doesn't really matter what we do here - gfxRect outerVisible(outerRect.x, outerRect.y, outerRect.width, outerRect.height); - gfxRect layerVisible = transform.Inverse().ProjectRectBounds(outerVisible); - if (aLayerContentsVisibleRect) { - NS_ASSERTION(aLayerContentsVisibleRect->width >= 0 && - aLayerContentsVisibleRect->height >= 0, - "Bad layer contents rectangle"); - // restrict to aLayerContentsVisibleRect before call GfxRectToIntRect, - // in case layerVisible is extremely large (as it can be when - // projecting through the inverse of a 3D transform) - gfxRect layerContentsVisible( - aLayerContentsVisibleRect->x, aLayerContentsVisibleRect->y, - aLayerContentsVisibleRect->width, aLayerContentsVisibleRect->height); - layerVisible.IntersectRect(layerVisible, layerContentsVisible); - } - layerVisible.RoundOut(); - nsIntRect visRect; - if (gfxUtils::GfxRectToIntRect(layerVisible, &visRect)) { - *aOuterVisibleRegion = visRect; - } else { - aOuterVisibleRegion->SetEmpty(); - } + nsIntRegion rgn; + rgn.And(aLayerVisibleRegion, visibleRect); + aLayer->SetVisibleRegion(rgn); } - - aLayer->SetVisibleRegion(*aOuterVisibleRegion); -} - -void -ContainerState::SetOuterVisibleRegionForLayer(Layer* aLayer, - const nsIntRegion& aOuterVisibleRegion, - const nsIntRect* aLayerContentsVisibleRect) const -{ - nsIntRegion visRegion = aOuterVisibleRegion; - visRegion.MoveBy(mParameters.mOffset); - SetOuterVisibleRegion(aLayer, &visRegion, aLayerContentsVisibleRect); } nscolor @@ -1965,7 +1844,8 @@ static bool CanOptimizeAwayThebesLayer(ThebesLayerData* aData, FrameLayerBuilder* aLayerBuilder) { - if (!aLayerBuilder->IsBuildingRetainedLayers()) { + bool isRetained = aData->mLayer->Manager()->IsWidgetLayerManager(); + if (!isRetained) { return false; } @@ -1983,19 +1863,6 @@ CanOptimizeAwayThebesLayer(ThebesLayerData* aData, return aLayerBuilder->CheckInLayerTreeCompressionMode(); } -#ifdef DEBUG -static int32_t FindIndexOfLayerIn(nsTArray& aArray, - Layer* aLayer) -{ - for (uint32_t i = 0; i < aArray.Length(); ++i) { - if (aArray[i].mLayer == aLayer) { - return i; - } - } - return -1; -} -#endif - void ContainerState::PopThebesLayerData() { @@ -2008,10 +1875,9 @@ ContainerState::PopThebesLayerData() data->mDrawRegion, &data->mVisibleRegion, &data->mIsSolidColorInVisibleRegion); - - NewLayerEntry* newLayerEntry = &mNewChildLayers[data->mNewChildLayersIndex]; nsRefPtr layer; nsRefPtr imageContainer = data->CanOptimizeImageLayer(mBuilder); + if ((data->mIsSolidColorInVisibleRegion || imageContainer) && CanOptimizeAwayThebesLayer(data, mLayerBuilder)) { NS_ASSERTION(!(data->mIsSolidColorInVisibleRegion && imageContainer), @@ -2047,16 +1913,10 @@ ContainerState::PopThebesLayerData() layer = colorLayer; } - NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, - "Layer already in list???"); - NS_ASSERTION(newLayerEntry->mLayer == data->mLayer, - "Thebes 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; + NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???"); + AutoLayersArray::index_type index = mNewChildLayers.IndexOf(data->mLayer); + NS_ASSERTION(index != AutoLayersArray::NoIndex, "Thebes layer not found?"); + mNewChildLayers.InsertElementAt(index + 1, layer); // Hide the ThebesLayer. We leave it in the layer tree so that we // can find and recycle it later. @@ -2070,18 +1930,20 @@ ContainerState::PopThebesLayerData() layer->SetClipRect(nullptr); } - if (mLayerBuilder->IsBuildingRetainedLayers()) { - newLayerEntry->mVisibleRegion = data->mVisibleRegion; - newLayerEntry->mOpaqueRegion = data->mOpaqueRegion; - newLayerEntry->mHideAllLayersBelow = data->mHideAllLayersBelow; - if (nsLayoutUtils::GetScrollableFrameFor(newLayerEntry->mAnimatedGeometryRoot) && - !nsDisplayScrollLayer::IsConstructingScrollLayerForScrolledFrame(newLayerEntry->mAnimatedGeometryRoot)) { - // Async scrolling not currently active so we can propagate our opaque region - // up to the parent animated geometry root. - newLayerEntry->mOpaqueForAnimatedGeometryRootParent = true; - } - } else { - SetOuterVisibleRegionForLayer(layer, data->mVisibleRegion); + Matrix transform; + if (!layer->GetTransform().Is2D(&transform)) { + NS_ERROR("Only 2D transformations currently supported"); + } + + // ImageLayers are already configured with a visible region + if (!imageContainer) { + NS_ASSERTION(!transform.HasNonIntegerTranslation(), + "Matrix not just an integer translation?"); + // Convert from relative to the container to relative to the + // ThebesLayer itself. + nsIntRegion rgn = data->mVisibleRegion; + rgn.MoveBy(-GetTranslationForThebesLayer(data->mLayer)); + layer->SetVisibleRegion(rgn); } nsIntRegion transparentRegion; @@ -2123,14 +1985,14 @@ ContainerState::PopThebesLayerData() // data->mCommonClipCount may be -1 if we haven't put any actual // drawable items in this layer (i.e. it's only catching events). int32_t commonClipCount = std::max(0, data->mCommonClipCount); - SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion, commonClipCount); + SetupMaskLayer(layer, data->mItemClip, commonClipCount); // copy commonClipCount to the entry FrameLayerBuilder::ThebesLayerItemsEntry* entry = mLayerBuilder-> GetThebesLayerItemsEntry(static_cast(layer.get())); entry->mCommonClipCount = commonClipCount; } else { // mask layer for image and color layers - SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion); + SetupMaskLayer(layer, data->mItemClip); } uint32_t flags = 0; @@ -2212,28 +2074,39 @@ ContainerState::PopThebesLayerData() } static bool -IsItemAreaInWindowOpaqueRegion(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem, - const nsRect& aComponentAlphaBounds) +SuppressComponentAlpha(nsDisplayListBuilder* aBuilder, + nsDisplayItem* aItem, + const nsRect& aComponentAlphaBounds) { - if (!aItem->Frame()->PresContext()->IsChrome()) { - // Assume that Web content is always in the window opaque region. - return true; - } - if (aItem->ReferenceFrame() != aBuilder->RootReferenceFrame()) { - // aItem is probably in some transformed subtree. - // We're not going to bother figuring out where this landed, we're just - // going to assume it might have landed over a transparent part of - // the window. + const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion(); + if (!windowTransparentRegion || windowTransparentRegion->IsEmpty()) return false; + + // Suppress component alpha for items in the toplevel window that are over + // the window translucent area + nsIFrame* f = aItem->Frame(); + nsIFrame* ref = aBuilder->RootReferenceFrame(); + if (f->PresContext() != ref->PresContext()) + return false; + + for (nsIFrame* t = f; t; t = t->GetParent()) { + if (t->IsTransformed()) + return false; } - return aBuilder->GetWindowOpaqueRegion().Contains(aComponentAlphaBounds); + + return windowTransparentRegion->Intersects(aComponentAlphaBounds); +} + +static bool +WindowHasTransparency(nsDisplayListBuilder* aBuilder) +{ + const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion(); + return windowTransparentRegion && !windowTransparentRegion->IsEmpty(); } void ThebesLayerData::Accumulate(ContainerState* aState, nsDisplayItem* aItem, - const nsIntRegion& aClippedOpaqueRegion, const nsIntRect& aVisibleRect, const nsIntRect& aDrawRect, const DisplayItemClip& aClip) @@ -2314,9 +2187,19 @@ ThebesLayerData::Accumulate(ContainerState* aState, mDrawRegion.SimplifyOutward(4); } - if (!aClippedOpaqueRegion.IsEmpty()) { - nsIntRegionRectIterator iter(aClippedOpaqueRegion); - for (const nsIntRect* r = iter.Next(); r; r = iter.Next()) { + bool snap; + nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap); + if (!opaque.IsEmpty()) { + nsRegion opaqueClipped; + nsRegionRectIterator iter(opaque); + for (const nsRect* r = iter.Next(); r; r = iter.Next()) { + opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInward(*r)); + } + + nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap); + + nsIntRegionRectIterator iter2(opaquePixels); + for (const nsIntRect* r = iter2.Next(); r; r = iter2.Next()) { // We don't use SimplifyInward here since it's not defined exactly // what it will discard. For our purposes the most important case // is a large opaque background at the bottom of z-order (e.g., @@ -2327,7 +2210,9 @@ ThebesLayerData::Accumulate(ContainerState* aState, // Opaque display items in chrome documents whose window is partially // transparent are always added to the opaque region. This helps ensure // that we get as much subpixel-AA as possible in the chrome. - if (tmp.GetNumRects() <= 4 || aItem->Frame()->PresContext()->IsChrome()) { + if (tmp.GetNumRects() <= 4 || + (WindowHasTransparency(aState->mBuilder) && + aItem->Frame()->PresContext()->IsChrome())) { mOpaqueRegion = tmp; } } @@ -2339,11 +2224,10 @@ ThebesLayerData::Accumulate(ContainerState* aState, nsIntRect componentAlphaRect = aState->ScaleToOutsidePixels(componentAlpha, false).Intersect(aVisibleRect); if (!mOpaqueRegion.Contains(componentAlphaRect)) { - if (IsItemAreaInWindowOpaqueRegion(aState->mBuilder, aItem, - componentAlpha.Intersect(aItem->GetVisibleRect()))) { - mNeedComponentAlpha = true; - } else { + if (SuppressComponentAlpha(aState->mBuilder, aItem, componentAlpha)) { aItem->DisableComponentAlpha(); + } else { + mNeedComponentAlpha = true; } } } @@ -2420,18 +2304,8 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, thebesLayerData->mReferenceFrame = aItem->ReferenceFrame(); thebesLayerData->mSingleItemFixedToViewport = aShouldFixToViewport; - NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, layer) < 0, - "Layer already in list???"); - thebesLayerData->mNewChildLayersIndex = mNewChildLayers.Length(); - NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement(); - newLayerEntry->mLayer = layer.forget(); - newLayerEntry->mAnimatedGeometryRoot = aAnimatedGeometryRoot; - newLayerEntry->mFixedPosFrameForLayerData = thebesLayerData->mFixedPosFrameForLayerData; - // newLayerEntry->mOpaqueRegion is filled in later from - // thebesLayerData->mOpaqueRegion, if necessary. - - // Allocate another entry for this layer's optimization to ColorLayer/ImageLayer - mNewChildLayers.AppendElement(); + NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???"); + *mNewChildLayers.AppendElement() = layer.forget(); } else { thebesLayerData = mThebesLayerDataStack[lowestUsableLayerWithScrolledRoot]; } @@ -2536,86 +2410,6 @@ ContainerState::ChooseAnimatedGeometryRoot(const nsDisplayList& aList, return false; } -/* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem - * is an overlay scrollbar item for the same scroll frame. - */ -static bool -IsScrollLayerItemAndOverlayScrollbarForScrollFrame( - nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem) -{ - if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER && - aPotentialScrollbarItem && - aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER && - LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) { - nsDisplayScrollLayer* scrollItem = - static_cast(aPotentialScrollItem); - nsDisplayOwnLayer* layerItem = - static_cast(aPotentialScrollbarItem); - if ((layerItem->GetFlags() & - (nsDisplayOwnLayer::VERTICAL_SCROLLBAR | - nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) && - layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) { - return true; - } - } - return false; -} - -bool -ContainerState::ItemCoversScrollableArea(nsDisplayItem* aItem, const nsRegion& aOpaque) -{ - nsIPresShell* presShell = aItem->Frame()->PresContext()->PresShell(); - nsIFrame* rootFrame = presShell->GetRootFrame(); - if (mContainerFrame != rootFrame) { - return false; - } - nsRect scrollableArea; - if (presShell->IsScrollPositionClampingScrollPortSizeSet()) { - scrollableArea = nsRect(nsPoint(0, 0), - presShell->GetScrollPositionClampingScrollPortSize()); - } else { - scrollableArea = rootFrame->GetRectRelativeToSelf(); - } - return aOpaque.Contains(scrollableArea); -} - -nsIntRegion -ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem, - const nsIFrame* aAnimatedGeometryRoot, - const nsIFrame* aFixedPosFrame, - const DisplayItemClip& aClip, - nsDisplayList* aList, - bool* aHideAllLayersBelow) -{ - bool snapOpaque; - nsRegion opaque = aItem->GetOpaqueRegion(mBuilder, &snapOpaque); - nsIntRegion opaquePixels; - if (!opaque.IsEmpty()) { - nsRegion opaqueClipped; - nsRegionRectIterator iter(opaque); - for (const nsRect* r = iter.Next(); r; r = iter.Next()) { - opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInward(*r)); - } - if (aAnimatedGeometryRoot == mContainerAnimatedGeometryRoot && - aFixedPosFrame == mContainerFixedPosFrame && - !aList->IsOpaque() && - opaqueClipped.Contains(mContainerBounds)) { - aList->SetIsOpaque(); - } - // Add opaque areas to the "exclude glass" region. Only do this for - // ThebesLayers which are direct children of the root layer; this means - // they can't have transforms or opacity wrapping them. - if (!mContainerLayer->GetParent()) { - mBuilder->AddWindowOpaqueRegion(opaqueClipped); - } - opaquePixels = ScaleRegionToInsidePixels(opaqueClipped, snapOpaque); - if (aFixedPosFrame && ItemCoversScrollableArea(aItem, opaque)) { - *aHideAllLayersBelow = true; - } - } - return opaquePixels; -} - /* * Iterate through the non-clip items in aList and its descendants. * For each item we compute the effective clip rect. Each item is assigned @@ -2631,7 +2425,7 @@ ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem, * of ContainerState::Finish. */ void -ContainerState::ProcessDisplayItems(nsDisplayList* aList, +ContainerState::ProcessDisplayItems(const nsDisplayList& aList, uint32_t aFlags) { PROFILER_LABEL("ContainerState", "ProcessDisplayItems", @@ -2644,7 +2438,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList, // layer, so we need to choose which active scrolled root to use for all // items. if (aFlags & NO_COMPONENT_ALPHA) { - if (ChooseAnimatedGeometryRoot(*aList, &lastAnimatedGeometryRoot)) { + if (ChooseAnimatedGeometryRoot(aList, &lastAnimatedGeometryRoot)) { topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame); } } @@ -2652,42 +2446,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList, int32_t maxLayers = nsDisplayItem::MaxActiveLayers(); int layerCount = 0; - nsDisplayList savedItems; - nsDisplayItem* item; - while ((item = aList->RemoveBottom()) != nullptr) { - // Peek ahead to the next item and try merging with it or swapping with it - // if necessary. - nsDisplayItem* aboveItem; - while ((aboveItem = aList->GetBottom()) != nullptr) { - if (aboveItem->TryMerge(mBuilder, item)) { - aList->RemoveBottom(); - item->~nsDisplayItem(); - item = aboveItem; - } else if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(aboveItem, item)) { - // If an overlay scrollbar item is between a scroll layer item and the - // other scroll layer items that we need to merge with just move the - // scrollbar item up, that way it will be on top of the scrolled content - // and we can try to merge all the scroll layer items. - aList->RemoveBottom(); - aList->AppendToBottom(item); - item = aboveItem; - } else { - break; - } - } - - nsDisplayList* itemSameCoordinateSystemChildren - = item->GetSameCoordinateSystemChildren(); - if (itemSameCoordinateSystemChildren) { - if (item->ShouldFlattenAway(mBuilder)) { - aList->AppendToBottom(itemSameCoordinateSystemChildren); - item->~nsDisplayItem(); - continue; - } - } - - savedItems.AppendToTop(item); - + for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item), "items in a container layer should all have the same app units per dev pixel"); @@ -2705,9 +2464,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList, itemDrawRect.IntersectRect(itemDrawRect, clipRect); clipRect.MoveBy(mParameters.mOffset); } -#ifdef DEBUG - ((nsRect&)mAccumulatedChildBounds).UnionRect(mAccumulatedChildBounds, itemContent); -#endif + mBounds.UnionRect(mBounds, itemContent); itemVisibleRect.IntersectRect(itemVisibleRect, itemDrawRect); LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters); @@ -2773,12 +2530,13 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList, continue; } + if (itemType == nsDisplayItem::TYPE_TRANSFORM) { + mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr; + } else { + mParameters.mAncestorClipRect = nullptr; + } + // Just use its layer. - // Set layerContentsVisibleRect.width/height to -1 to indicate we - // currently don't know. If BuildContainerLayerFor gets called by - // item->BuildLayer, this will be set to a proper rect. - nsIntRect layerContentsVisibleRect(0, 0, -1, -1); - mParameters.mLayerContentsVisibleRect = &layerContentsVisibleRect; nsRefPtr ownLayer = item->BuildLayer(mBuilder, mManager, mParameters); if (!ownLayer) { continue; @@ -2828,7 +2586,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList, // (async animations or an empty transaction), so we need to put items // that the transform item can potentially move under into a layer // above this item. - if (itemType == nsDisplayItem::TYPE_TRANSFORM && + if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM && nsDisplayTransform::ShouldPrerenderTransformedContent(mBuilder, item->Frame(), false)) { @@ -2853,45 +2611,25 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList, data->AddDrawAboveRegion(itemDrawRect); } } + itemVisibleRect.MoveBy(mParameters.mOffset); + if (item->SetVisibleRegionOnLayer()) { + SetVisibleRegionForLayer(ownLayer, ownLayer->GetVisibleRegion(), itemVisibleRect); + } // rounded rectangle clipping using mask layers // (must be done after visible rect is set on layer) if (itemClip.IsRectClippedByRoundedCorner(itemContent)) { - SetupMaskLayer(ownLayer, itemClip, itemVisibleRect); + SetupMaskLayer(ownLayer, itemClip); } ContainerLayer* oldContainer = ownLayer->GetParent(); if (oldContainer && oldContainer != mContainerLayer) { oldContainer->RemoveChild(ownLayer); } - NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0, + NS_ASSERTION(!mNewChildLayers.Contains(ownLayer), "Layer already in list???"); - NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement(); - newLayerEntry->mLayer = ownLayer; - newLayerEntry->mAnimatedGeometryRoot = animatedGeometryRoot; - newLayerEntry->mFixedPosFrameForLayerData = fixedPosFrame; - // nsDisplayTransform::BuildLayer must set layerContentsVisibleRect. - // We rely on this to ensure 3D transforms compute a reasonable - // layer visible region. - NS_ASSERTION(itemType != nsDisplayItem::TYPE_TRANSFORM || - layerContentsVisibleRect.width >= 0, - "Transform items must set layerContentsVisibleRect!"); - if (mLayerBuilder->IsBuildingRetainedLayers()) { - newLayerEntry->mLayerContentsVisibleRect = layerContentsVisibleRect; - newLayerEntry->mVisibleRegion = itemVisibleRect; - newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item, - animatedGeometryRoot, fixedPosFrame, itemClip, aList, - &newLayerEntry->mHideAllLayersBelow); - } else { - SetOuterVisibleRegionForLayer(ownLayer, itemVisibleRect, - layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr); - } - if (itemType == nsDisplayItem::TYPE_SCROLL_LAYER) { - nsDisplayScrollLayer* scrollItem = static_cast(item); - newLayerEntry->mOpaqueForAnimatedGeometryRootParent = - scrollItem->IsDisplayPortOpaque(); - } + mNewChildLayers.AppendElement(ownLayer); /** * No need to allocate geometry for items that aren't @@ -2903,42 +2641,32 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList, topLeft, nullptr, dummy); } else { - ThebesLayerData* thebesLayerData = + ThebesLayerData* data = FindThebesLayerFor(item, itemVisibleRect, animatedGeometryRoot, topLeft, shouldFixToViewport); if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) { nsDisplayLayerEventRegions* eventRegions = static_cast(item); - thebesLayerData->AccumulateEventRegions(eventRegions->HitRegion(), - eventRegions->MaybeHitRegion(), - eventRegions->DispatchToContentHitRegion()); + data->AccumulateEventRegions(eventRegions->HitRegion(), + eventRegions->MaybeHitRegion(), + eventRegions->DispatchToContentHitRegion()); } else { // check to see if the new item has rounded rect clips in common with // other items in the layer - thebesLayerData->UpdateCommonClipCount(itemClip); + data->UpdateCommonClipCount(itemClip); + data->Accumulate(this, item, itemVisibleRect, itemDrawRect, itemClip); nsAutoPtr geometry(item->AllocateGeometry(mBuilder)); - InvalidateForLayerChange(item, thebesLayerData->mLayer, itemClip, topLeft, geometry); + InvalidateForLayerChange(item, data->mLayer, itemClip, topLeft, geometry); - mLayerBuilder->AddThebesDisplayItem(thebesLayerData, item, itemClip, itemVisibleRect, - *this, layerState, topLeft, geometry); - nsIntRegion opaquePixels = ComputeOpaqueRect(item, - animatedGeometryRoot, thebesLayerData->mFixedPosFrameForLayerData, - itemClip, aList, - &thebesLayerData->mHideAllLayersBelow); - thebesLayerData->Accumulate(this, item, opaquePixels, - itemVisibleRect, itemDrawRect, itemClip); + mLayerBuilder->AddThebesDisplayItem(data, item, itemClip, + mContainerFrame, + layerState, topLeft, + geometry); } } - - if (itemSameCoordinateSystemChildren && - itemSameCoordinateSystemChildren->NeedsTransparentSurface()) { - aList->SetNeedsTransparentSurface(); - } } - - aList->AppendToTop(&savedItems); } void @@ -3080,8 +2808,7 @@ void FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData, nsDisplayItem* aItem, const DisplayItemClip& aClip, - const nsIntRect& aItemVisibleRect, - const ContainerState& aContainerState, + nsIFrame* aContainerLayerFrame, LayerState aLayerState, const nsPoint& aTopLeft, nsAutoPtr aGeometry) @@ -3121,7 +2848,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData, ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(layer); if (entry) { - entry->mContainerLayerFrame = aContainerState.GetContainerFrame(); + entry->mContainerLayerFrame = aContainerLayerFrame; if (entry->mContainerLayerGeneration == 0) { entry->mContainerLayerGeneration = mContainerLayerGeneration; } @@ -3145,12 +2872,6 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayerData* aLayerData, return; } - bool snap; - nsRect visibleRect = - aItem->GetVisibleRect().Intersect(aItem->GetBounds(mDisplayListBuilder, &snap)); - nsIntRegion rgn = visibleRect.ToOutsidePixels(thebesData->mAppUnitsPerDevPixel); - SetOuterVisibleRegion(tmpLayer, &rgn); - // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been // stored in layerBuilder. Manually add it now. if (mRetainingManager) { @@ -3343,126 +3064,21 @@ ContainerState::CollectOldLayers() } } -struct OpaqueRegionEntry { - const nsIFrame* mAnimatedGeometryRoot; - const nsIFrame* mFixedPosFrameForLayerData; - nsIntRegion mOpaqueRegion; -}; - -static OpaqueRegionEntry* -FindOpaqueRegionEntry(nsTArray& aEntries, - const nsIFrame* aAnimatedGeometryRoot, - const nsIFrame* aFixedPosFrameForLayerData) -{ - for (uint32_t i = 0; i < aEntries.Length(); ++i) { - OpaqueRegionEntry* d = &aEntries[i]; - if (d->mAnimatedGeometryRoot == aAnimatedGeometryRoot && - d->mFixedPosFrameForLayerData == aFixedPosFrameForLayerData) { - return d; - } - } - return nullptr; -} - void -ContainerState::ApplyOcclusionCulling(nsIntRegion* aOpaqueRegionForContainer) -{ - nsAutoTArray opaqueRegions; - bool hideAll = false; - int32_t opaqueRegionForContainer = -1; - - for (int32_t i = mNewChildLayers.Length() - 1; i >= 0; --i) { - NewLayerEntry* e = &mNewChildLayers.ElementAt(i); - if (!e->mLayer) { - continue; - } - - OpaqueRegionEntry* data = FindOpaqueRegionEntry(opaqueRegions, - e->mAnimatedGeometryRoot, e->mFixedPosFrameForLayerData); - - if (hideAll) { - e->mVisibleRegion.SetEmpty(); - } else if (data) { - e->mVisibleRegion.Sub(e->mVisibleRegion, data->mOpaqueRegion); - } - - if (!e->mOpaqueRegion.IsEmpty()) { - const nsIFrame* animatedGeometryRootToCover = e->mAnimatedGeometryRoot; - if (e->mOpaqueForAnimatedGeometryRootParent && - nsLayoutUtils::GetAnimatedGeometryRootForFrame(e->mAnimatedGeometryRoot->GetParent(), - mContainerAnimatedGeometryRoot) - == mContainerAnimatedGeometryRoot) { - animatedGeometryRootToCover = mContainerAnimatedGeometryRoot; - data = FindOpaqueRegionEntry(opaqueRegions, - animatedGeometryRootToCover, e->mFixedPosFrameForLayerData); - } - - if (!data) { - if (animatedGeometryRootToCover == mContainerAnimatedGeometryRoot && - !e->mFixedPosFrameForLayerData) { - NS_ASSERTION(opaqueRegionForContainer == -1, "Already found it?"); - opaqueRegionForContainer = opaqueRegions.Length(); - } - data = opaqueRegions.AppendElement(); - data->mAnimatedGeometryRoot = animatedGeometryRootToCover; - data->mFixedPosFrameForLayerData = e->mFixedPosFrameForLayerData; - } - data->mOpaqueRegion.Or(data->mOpaqueRegion, e->mOpaqueRegion); - if (e->mHideAllLayersBelow) { - hideAll = true; - } - } - - SetOuterVisibleRegionForLayer(e->mLayer, e->mVisibleRegion, - e->mLayerContentsVisibleRect.width >= 0 ? &e->mLayerContentsVisibleRect : nullptr); - - if (e->mLayer->GetType() == Layer::TYPE_READBACK) { - // ReadbackLayers need to accurately read what's behind them. So, - // we don't want to do any occlusion culling of layers behind them. - // Theoretically we could just punch out the ReadbackLayer's rectangle - // from all mOpaqueRegions, but that's probably not worth doing. - opaqueRegions.Clear(); - opaqueRegionForContainer = -1; - } - } - - if (opaqueRegionForContainer >= 0) { - aOpaqueRegionForContainer->Or(*aOpaqueRegionForContainer, - opaqueRegions[opaqueRegionForContainer].mOpaqueRegion); - } -} - -void -ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData, - const nsIntRect& aContainerPixelBounds, - nsDisplayList* aChildItems) +ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData) { while (!mThebesLayerDataStack.IsEmpty()) { PopThebesLayerData(); } - NS_ASSERTION(mContainerBounds.IsEqualInterior(mAccumulatedChildBounds), - "Bounds computation mismatch"); uint32_t textContentFlags = 0; - if (mLayerBuilder->IsBuildingRetainedLayers()) { - nsIntRegion containerOpaqueRegion; - ApplyOcclusionCulling(&containerOpaqueRegion); - if (containerOpaqueRegion.Contains(aContainerPixelBounds)) { - aChildItems->SetIsOpaque(); - } - } - // Make sure that current/existing layers are added to the parent and are // in the correct order. Layer* layer = nullptr; - Layer* prevChild = nullptr; - for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i, prevChild = layer) { - if (!mNewChildLayers[i].mLayer) { - continue; - } - - layer = mNewChildLayers[i].mLayer; + for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i) { + Layer* prevChild = i == 0 ? nullptr : mNewChildLayers[i - 1].get(); + layer = mNewChildLayers[i]; if (!layer->GetVisibleRegion().IsEmpty()) { textContentFlags |= layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA; @@ -3650,8 +3266,8 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder, aOutgoingScale.mInActiveTransformedSubtree = true; } } - if (aLayerBuilder->IsBuildingRetainedLayers() && - (!canDraw2D || transform2d.HasNonIntegerTranslation())) { + bool isRetained = aLayer->Manager()->IsWidgetLayerManager(); + if (isRetained && (!canDraw2D || transform2d.HasNonIntegerTranslation())) { aOutgoingScale.mDisableSubpixelAntialiasingInDescendants = true; } return true; @@ -3697,7 +3313,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, LayerManager* aManager, nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem, - nsDisplayList* aChildren, + const nsDisplayList& aChildren, const ContainerLayerParameters& aParameters, const gfx3DMatrix* aTransform, uint32_t aFlags) @@ -3761,19 +3377,13 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, // early exit because later, invalidation will walk up the frame tree to // determine which thebes layer gets invalidated. Since an empty layer // should never have anything to paint, it should never be invalidated. - NS_ASSERTION(aChildren->IsEmpty(), "Should have no children"); + NS_ASSERTION(aChildren.IsEmpty(), "Should have no children"); return containerLayer.forget(); } ContainerLayerParameters scaleParameters; - nsRect bounds = aChildren->GetBounds(aBuilder); - nsRect childrenVisible = - aContainerItem ? aContainerItem->GetVisibleRectForChildren() : - aContainerFrame->GetVisualOverflowRectRelativeToSelf(); - if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, - bounds.Intersect(childrenVisible), - aTransform, aParameters, - containerLayer, state, scaleParameters)) { + if (!ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aChildren.GetVisibleRect(), + aTransform, aParameters, containerLayer, state, scaleParameters)) { return nullptr; } @@ -3792,8 +3402,9 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, LayerManagerData* data = static_cast (aManager->GetUserData(&gLayerManagerUserData)); + nsRect bounds; nsIntRect pixBounds; - nscoord appUnitsPerDevPixel; + int32_t appUnitsPerDevPixel; uint32_t stateFlags = 0; if ((aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) && mRetainingManager && !mRetainingManager->AreComponentAlphaLayersEnabled()) { @@ -3802,7 +3413,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, uint32_t flags; while (true) { ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(), - aContainerFrame, aContainerItem, bounds, + aContainerFrame, aContainerItem, containerLayer, scaleParameters); state.ProcessDisplayItems(aChildren, stateFlags); @@ -3810,9 +3421,10 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, // Set CONTENT_COMPONENT_ALPHA if any of our children have it. // This is suboptimal ... a child could have text that's over transparent // pixels in its own layer, but over opaque parts of previous siblings. + state.Finish(&flags, data); + bounds = state.GetChildrenBounds(); pixBounds = state.ScaleToOutsidePixels(bounds, false); appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel(); - state.Finish(&flags, data, pixBounds, aChildren); if ((flags & Layer::CONTENT_COMPONENT_ALPHA) && mRetainingManager && @@ -3833,9 +3445,17 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, break; } + NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds"); + pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y)); + if (aParameters.mAncestorClipRect && !(aFlags & CONTAINER_NOT_CLIPPED_BY_ANCESTORS)) { + SetVisibleRegionForLayer(containerLayer, nsIntRegion(pixBounds), + *aParameters.mAncestorClipRect); + } else { + containerLayer->SetVisibleRegion(pixBounds); + } // Make sure that rounding the visible region out didn't add any area // we won't paint - if (aChildren->IsOpaque() && !aChildren->NeedsTransparentSurface()) { + if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) { bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale); if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) { // Clear CONTENT_COMPONENT_ALPHA @@ -3843,14 +3463,6 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, } } containerLayer->SetContentFlags(flags); - // If aContainerItem is non-null some BuildContainerLayer further up the - // call stack is responsible for setting containerLayer's visible region. - if (!aContainerItem) { - containerLayer->SetVisibleRegion(pixBounds); - } - if (aParameters.mLayerContentsVisibleRect) { - *aParameters.mLayerContentsVisibleRect = pixBounds + scaleParameters.mOffset; - } mContainerLayerGeneration = oldGeneration; nsPresContext::ClearNotifySubDocInvalidationData(containerLayer); @@ -4032,8 +3644,11 @@ FrameLayerBuilder::RecomputeVisibilityForItems(nsTArray& aIt float aYScale) { uint32_t i; - // Update visible regions. We perform visibility analysis to take account - // of occlusion culling. + // Update visible regions. We need perform visibility analysis again + // because we may be asked to draw into part of a ThebesLayer that + // isn't actually visible in the window (e.g., because a ThebesLayer + // expanded its visible region to a rectangle internally), in which + // case the mVisibleRect stored in the display item may be wrong. nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel); visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel), NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel)); @@ -4264,17 +3879,13 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, // ThebesLayer gfxContextMatrixAutoSaveRestore saveMatrix(aContext); nsIntPoint offset = GetTranslationForThebesLayer(aLayer); - nsPresContext* presContext = entry->mContainerLayerFrame->PresContext(); - if (!layerBuilder->GetContainingThebesLayerData()) { - // Recompute visibility of items in our ThebesLayer. Note that this - // recomputes visibility for all descendants of our display items too, - // so there's no need to do this for the items in inactive ThebesLayers. - int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); - RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw, - offset, appUnitsPerDevPixel, - userData->mXScale, userData->mYScale); - } + nsPresContext* presContext = entry->mContainerLayerFrame->PresContext(); + int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); + + RecomputeVisibilityForItems(entry->mItems, builder, aRegionToDraw, + offset, appUnitsPerDevPixel, + userData->mXScale, userData->mYScale); nsRefPtr rc = new nsRenderingContext(); rc->Init(presContext->DeviceContext(), aContext); @@ -4378,9 +3989,7 @@ SetClipCount(ThebesDisplayItemLayerUserData* aThebesData, } void -ContainerState::SetupMaskLayer(Layer *aLayer, - const DisplayItemClip& aClip, - const nsIntRegion& aLayerVisibleRegion, +ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip, uint32_t aRoundedRectClipCount) { // if the number of clips we are going to mask has decreased, then aLayer might have @@ -4394,7 +4003,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, } // don't build an unnecessary mask - nsIntRect layerBounds = aLayerVisibleRegion.GetBounds(); + nsIntRect layerBounds = aLayer->GetVisibleRegion().GetBounds(); if (aClip.GetRoundedRectCount() == 0 || aRoundedRectClipCount == 0 || layerBounds.IsEmpty()) { diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index 72fdd814693..fad65d41d79 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -32,7 +32,6 @@ class ThebesLayer; class FrameLayerBuilder; class LayerManagerData; class ThebesLayerData; -class ContainerState; enum LayerState { LAYER_NONE, @@ -58,44 +57,34 @@ public: bool mIsInfinite; }; -struct NewLayerEntry; - struct ContainerLayerParameters { - ContainerLayerParameters() - : mXScale(1) - , mYScale(1) - , mLayerContentsVisibleRect(nullptr) - , mInTransformedSubtree(false) - , mInActiveTransformedSubtree(false) - , mDisableSubpixelAntialiasingInDescendants(false) + ContainerLayerParameters() : + mXScale(1), mYScale(1), mAncestorClipRect(nullptr), + mInTransformedSubtree(false), mInActiveTransformedSubtree(false), + mDisableSubpixelAntialiasingInDescendants(false) {} - ContainerLayerParameters(float aXScale, float aYScale) - : mXScale(aXScale) - , mYScale(aYScale) - , mLayerContentsVisibleRect(nullptr) - , mInTransformedSubtree(false) - , mInActiveTransformedSubtree(false) - , mDisableSubpixelAntialiasingInDescendants(false) + ContainerLayerParameters(float aXScale, float aYScale) : + mXScale(aXScale), mYScale(aYScale), mAncestorClipRect(nullptr), + mInTransformedSubtree(false), mInActiveTransformedSubtree(false), + mDisableSubpixelAntialiasingInDescendants(false) {} ContainerLayerParameters(float aXScale, float aYScale, const nsIntPoint& aOffset, - const ContainerLayerParameters& aParent) - : mXScale(aXScale) - , mYScale(aYScale) - , mLayerContentsVisibleRect(nullptr) - , mOffset(aOffset) - , mInTransformedSubtree(aParent.mInTransformedSubtree) - , mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree) - , mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants) + const ContainerLayerParameters& aParent) : + mXScale(aXScale), mYScale(aYScale), mAncestorClipRect(nullptr), + mOffset(aOffset), + mInTransformedSubtree(aParent.mInTransformedSubtree), + mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree), + mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants) {} float mXScale, mYScale; /** - * If non-null, the rectangle in which BuildContainerLayerFor stores the - * visible rect of the layer, in the coordinate system of the created layer. + * An ancestor clip rect that can be applied to restrict the visibility + * of this container. Null if none available. */ - nsIntRect* mLayerContentsVisibleRect; + const nsIntRect* mAncestorClipRect; /** - * An offset to apply to all child layers created. + * An offset to append to the transform set on all child layers created. */ nsIntPoint mOffset; @@ -218,16 +207,13 @@ public: * is set based on what's in the layer. * The container layer is transformed by aTransform (if non-null), and * the result is transformed by the scale factors in aContainerParameters. - * aChildren is modified due to display item merging and flattening. - * The visible region of the returned layer is set only if aContainerItem - * is null. */ already_AddRefed BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, LayerManager* aManager, nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem, - nsDisplayList* aChildren, + const nsDisplayList& aChildren, const ContainerLayerParameters& aContainerParameters, const gfx3DMatrix* aTransform, uint32_t aFlags = 0); @@ -313,8 +299,7 @@ public: void AddThebesDisplayItem(ThebesLayerData* aLayer, nsDisplayItem* aItem, const DisplayItemClip& aClip, - const nsIntRect& aItemVisibleRect, - const ContainerState& aContainerState, + nsIFrame* aContainerLayerFrame, LayerState aLayerState, const nsPoint& aTopLeft, nsAutoPtr aGeometry); @@ -611,11 +596,6 @@ public: return mContainingThebesLayer; } - bool IsBuildingRetainedLayers() - { - return !mContainingThebesLayer && mRetainingManager; - } - /** * Attempt to build the most compressed layer tree possible, even if it means * throwing away existing retained buffers. diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 7bc84bc300d..c44f9834ffc 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -491,9 +491,10 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mIgnoreScrollFrame(nullptr), mLayerEventRegions(nullptr), mCurrentTableItem(nullptr), - mCurrentFrame(aReferenceFrame), - mCurrentReferenceFrame(aReferenceFrame), - mDirtyRect(-1,-1,-1,-1), + mFinalTransparentRegion(nullptr), + mCachedOffsetFrame(aReferenceFrame), + mCachedReferenceFrame(aReferenceFrame), + mCachedOffset(0, 0), mGlassDisplayItem(nullptr), mMode(aMode), mCurrentScrollParentId(FrameMetrics::NULL_SCROLL_ID), @@ -510,6 +511,7 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, mAllowMergingAndFlattening(true), mWillComputePluginGeometry(false), mInTransform(false), + mInFixedPos(false), mSyncDecodeImages(false), mIsPaintingToWindow(false), mIsCompositingCheap(false), @@ -615,6 +617,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame, nsIFrame* aScrollFrame, const nsIFrame* aReferenceFrame, ContainerLayer* aRoot, + const nsRect& aVisibleRect, const nsRect& aViewport, bool aForceNullScrollId, bool aIsRoot, @@ -623,6 +626,10 @@ static void RecordFrameMetrics(nsIFrame* aForFrame, int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel(); LayoutDeviceToLayerScale resolution(aContainerParameters.mXScale, aContainerParameters.mYScale); + nsIntRect visible = aVisibleRect.ScaleToNearestPixels( + resolution.scale, resolution.scale, auPerDevPixel); + aRoot->SetVisibleRegion(visible); + nsIPresShell* presShell = presContext->GetPresShell(); FrameMetrics metrics; metrics.mViewport = CSSRect::FromAppUnits(aViewport); @@ -880,11 +887,11 @@ void nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect) { PresShellState* state = mPresShellStates.AppendElement(); + if (!state) + return; state->mPresShell = aReferenceFrame->PresContext()->PresShell(); state->mCaretFrame = nullptr; state->mFirstFrameMarkedForDisplay = mFramesMarkedForDisplay.Length(); - state->mPrevDirtyRect = mDirtyRect; - mDirtyRect = aDirtyRect; state->mPresShell->UpdateCanvasBackground(); @@ -928,10 +935,12 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame, void nsDisplayListBuilder::LeavePresShell(nsIFrame* aReferenceFrame, const nsRect& aDirtyRect) { - NS_ASSERTION(CurrentPresShellState()->mPresShell == - aReferenceFrame->PresContext()->PresShell(), - "Presshell mismatch"); - mDirtyRect = CurrentPresShellState()->mPrevDirtyRect; + if (CurrentPresShellState()->mPresShell != aReferenceFrame->PresContext()->PresShell()) { + // Must have not allocated a state for this presshell, presumably due + // to OOM. + return; + } + ResetMarkedFramesForDisplayList(); mPresShellStates.SetLength(mPresShellStates.Length() - 1); } @@ -1016,11 +1025,16 @@ void nsDisplayListSet::MoveTo(const nsDisplayListSet& aDestination) const aDestination.Outlines()->AppendToTop(Outlines()); } -static void -MoveListTo(nsDisplayList* aList, nsTArray* aElements) { +void +nsDisplayList::FlattenTo(nsTArray* aElements) { nsDisplayItem* item; - while ((item = aList->RemoveBottom()) != nullptr) { - aElements->AppendElement(item); + while ((item = RemoveBottom()) != nullptr) { + if (item->GetType() == nsDisplayItem::TYPE_WRAP_LIST) { + item->GetSameCoordinateSystemChildren()->FlattenTo(aElements); + item->~nsDisplayItem(); + } else { + aElements->AppendElement(item); + } } } @@ -1033,15 +1047,6 @@ nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const { return bounds; } -nsRect -nsDisplayList::GetVisibleRect() const { - nsRect result; - for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) { - result.UnionRect(result, i->GetVisibleRect()); - } - return result; -} - bool nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion, @@ -1052,7 +1057,8 @@ nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder, nsRegion r; r.And(*aVisibleRegion, GetBounds(aBuilder)); return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, - r.GetBounds(), aDisplayPortFrame); + r.GetBounds(), r.GetBounds(), + aDisplayPortFrame); } static nsRegion @@ -1087,10 +1093,36 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) return opaqueClipped; } +/* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem + * is an overlay scrollbar item for the same scroll frame. + */ +static bool +IsScrollLayerItemAndOverlayScrollbarForScrollFrame( + nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem) +{ + if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER && + aPotentialScrollbarItem && + aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER && + LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) { + nsDisplayScrollLayer* scrollItem = + static_cast(aPotentialScrollItem); + nsDisplayOwnLayer* layerItem = + static_cast(aPotentialScrollbarItem); + if ((layerItem->GetFlags() & + (nsDisplayOwnLayer::VERTICAL_SCROLLBAR | + nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) && + layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) { + return true; + } + } + return false; +} + bool nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion, const nsRect& aListVisibleBounds, + const nsRect& aAllowVisibleRegionExpansion, nsIFrame* aDisplayPortFrame) { #ifdef DEBUG nsRegion r; @@ -1099,38 +1131,113 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, "bad aListVisibleBounds"); #endif + mVisibleRect = aListVisibleBounds; bool anyVisible = false; nsAutoTArray elements; - MoveListTo(this, &elements); + FlattenTo(&elements); + + bool forceTransparentSurface = false; for (int32_t i = elements.Length() - 1; i >= 0; --i) { nsDisplayItem* item = elements[i]; + nsDisplayItem* belowItem = i < 1 ? nullptr : elements[i - 1]; + + nsDisplayList* list = item->GetSameCoordinateSystemChildren(); + if (aBuilder->AllowMergingAndFlattening()) { + if (belowItem && item->TryMerge(aBuilder, belowItem)) { + belowItem->~nsDisplayItem(); + elements.ReplaceElementsAt(i - 1, 1, item); + continue; + } + + // If an overlay scrollbar item is between a scroll layer item and the + // other scroll layer items that we need to merge with just move the + // scrollbar item up, that way it will be on top of the scrolled content + // and we can try to merge all the scroll layer items. + if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(item, belowItem)) { + elements[i] = belowItem; + elements[i-1] = item; + i++; + continue; + } + + if (list && item->ShouldFlattenAway(aBuilder)) { + // The elements on the list >= i no longer serve any use. + elements.SetLength(i); + list->FlattenTo(&elements); + i = elements.Length(); + item->~nsDisplayItem(); + continue; + } + } + nsRect bounds = item->GetClippedBounds(aBuilder); nsRegion itemVisible; itemVisible.And(*aVisibleRegion, bounds); item->mVisibleRect = itemVisible.GetBounds(); - if (item->ComputeVisibility(aBuilder, aVisibleRegion)) { + if (item->ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion.Intersect(bounds))) { anyVisible = true; + // If we're in a displayport, we need to make sure that fixed position + // items do not subtract from the visible region, as async scrolling + // may expose these occluded areas. + // If the item is fixed pos in the same document as the displayport + // then don't let it occlude this list. The only other case possible + // is that the fixed pos content is in a child document, in which it + // would scroll with the rest of the content. + bool occlude = true; + nsIPresShell* presShell = nullptr; + if (aDisplayPortFrame && item->IsInFixedPos()) { + if (item->Frame()->PresContext() == aDisplayPortFrame->PresContext()) { + occlude = false; + presShell = aDisplayPortFrame->PresContext()->PresShell(); + } + } + nsRegion opaque = TreatAsOpaque(item, aBuilder); - // Subtract opaque item from the visible region - aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque); + if (occlude) { + // Subtract opaque item from the visible region + aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque); + } else if (presShell && + presShell->IsScrollPositionClampingScrollPortSizeSet() && + !opaque.IsEmpty()) { + // We make an exception if the fixed position item would fully occlude + // the scroll position clamping scroll-port. In that case, it's very + // unlikely that it will become visible via async scrolling, so we let + // it occlude. + nsRect scrollClampingScrollPort(nsPoint(0, 0), + presShell->GetScrollPositionClampingScrollPortSize()); + if (opaque.Contains(scrollClampingScrollPort)) { + aVisibleRegion->SetEmpty(); + } + } + + if (aBuilder->NeedToForceTransparentSurfaceForItem(item) || + (list && list->NeedsTransparentSurface())) { + forceTransparentSurface = true; + } } AppendToBottom(item); } - mIsOpaque = !aVisibleRegion->Intersects(aListVisibleBounds); + mIsOpaque = !aVisibleRegion->Intersects(mVisibleRect); + mForceTransparentSurface = forceTransparentSurface; +#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) + mDidComputeVisibility = true; +#endif return anyVisible; } void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, - uint32_t aFlags) { + uint32_t aFlags) const { PROFILER_LABEL("nsDisplayList", "PaintRoot", js::ProfileEntry::Category::GRAPHICS); + PaintForFrame(aBuilder, aCtx, aBuilder->RootReferenceFrame(), aFlags); } @@ -1142,7 +1249,10 @@ void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, nsIFrame* aForFrame, - uint32_t aFlags) { + uint32_t aFlags) const { + NS_ASSERTION(mDidComputeVisibility, + "Must call ComputeVisibility before calling Paint"); + nsRefPtr layerManager; bool widgetTransaction = false; bool allowRetaining = false; @@ -1211,7 +1321,7 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, ContainerLayerParameters containerParameters (presShell->GetXResolution(), presShell->GetYResolution()); nsRefPtr root = layerBuilder-> - BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, this, + BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this, containerParameters, nullptr); nsIDocument* document = nullptr; @@ -1250,7 +1360,7 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, RecordFrameMetrics(aForFrame, rootScrollFrame, aBuilder->FindReferenceFrameFor(aForFrame), - root, viewport, + root, mVisibleRect, viewport, !isRoot, isRoot, containerParameters); if (usingDisplayport && !(root->GetContentFlags() & Layer::CONTENT_OPAQUE)) { @@ -1614,7 +1724,8 @@ nsDisplayItem::ZIndex() const bool nsDisplayItem::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { return !mVisibleRect.IsEmpty() && !IsInvisibleInRect(aVisibleRegion->GetBounds()); @@ -1632,10 +1743,8 @@ nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, // When we recompute visibility within layers we don't need to // expand the visible region for content behind plugins (the plugin // is not in the layer). - if (!ComputeVisibility(aBuilder, aVisibleRegion)) { - mVisibleRect = nsRect(); + if (!ComputeVisibility(aBuilder, aVisibleRegion, nsRect())) return false; - } nsRegion opaque = TreatAsOpaque(this, aBuilder); aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque); @@ -2030,6 +2139,7 @@ nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& a transform.Scale(mDestRect.width/imageSize.width, mDestRect.height/imageSize.height); aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); + aLayer->SetVisibleRegion(nsIntRect(0, 0, imageSize.width, imageSize.height)); } void @@ -2045,9 +2155,11 @@ nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder, bool nsDisplayBackgroundImage::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { - if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) { + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion)) { return false; } @@ -2144,6 +2256,23 @@ nsDisplayBackgroundImage::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aCo return false; } +bool +nsDisplayBackgroundImage::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame) +{ + if (!mBackgroundStyle) + return false; + if (!mBackgroundStyle->HasFixedBackground()) + return false; + + // If aFrame is mFrame or an ancestor in this document, and aFrame is + // not the viewport frame, then moving aFrame will move mFrame + // relative to the viewport, so our fixed-pos background will change. + return aFrame->GetParent() && + (aFrame == mFrame || + nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame)); +} + nsRect nsDisplayBackgroundImage::GetPositioningArea() { @@ -2792,8 +2921,10 @@ nsDisplayBoxShadowOuter::IsInvisibleInRect(const nsRect& aRect) bool nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { - if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) { + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion)) { return false; } @@ -2852,8 +2983,10 @@ nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder, bool nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { - if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) { + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion)) { return false; } @@ -2867,8 +3000,6 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, : nsDisplayItem(aBuilder, aFrame) , mOverrideZIndex(0) { - MOZ_COUNT_CTOR(nsDisplayWrapList); - mList.AppendToTop(aList); UpdateBounds(aBuilder); @@ -2884,28 +3015,28 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, mReferenceFrame = aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); - } else { - // If we're a transformed frame, then we need to find out if we're inside - // the nsDisplayTransform or outside of it. Frames inside the transform - // need mReferenceFrame == mFrame, outside needs the next ancestor - // reference frame. - // If we're inside the transform, then the nsDisplayItem constructor - // will have done the right thing. - // If we're outside the transform, then we should have only one child - // (since nsDisplayTransform wraps all actual content), and that child - // will have the correct reference frame set (since nsDisplayTransform - // handles this explictly). - // - // Preserve-3d can cause us to have multiple nsDisplayTransform - // children. - nsDisplayItem *i = mList.GetBottom(); - if (i && (!i->GetAbove() || i->GetType() == TYPE_TRANSFORM) && - i->Frame() == mFrame) { - mReferenceFrame = i->ReferenceFrame(); - mToReferenceFrame = i->ToReferenceFrame(); - } + return; + } + + // If we're a transformed frame, then we need to find out if we're inside + // the nsDisplayTransform or outside of it. Frames inside the transform + // need mReferenceFrame == mFrame, outside needs the next ancestor + // reference frame. + // If we're inside the transform, then the nsDisplayItem constructor + // will have done the right thing. + // If we're outside the transform, then we should have only one child + // (since nsDisplayTransform wraps all actual content), and that child + // will have the correct reference frame set (since nsDisplayTransform + // handles this explictly). + // + // Preserve-3d can cause us to have multiple nsDisplayTransform + // children. + nsDisplayItem *i = mList.GetBottom(); + if (i && (!i->GetAbove() || i->GetType() == TYPE_TRANSFORM) && + i->Frame() == mFrame) { + mReferenceFrame = i->ReferenceFrame(); + mToReferenceFrame = i->ToReferenceFrame(); } - mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame; } nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, @@ -2913,8 +3044,6 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, : nsDisplayItem(aBuilder, aFrame) , mOverrideZIndex(0) { - MOZ_COUNT_CTOR(nsDisplayWrapList); - mList.AppendToTop(aItem); UpdateBounds(aBuilder); @@ -2926,20 +3055,29 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, mReferenceFrame = aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); - } else { - // See the previous nsDisplayWrapList constructor - if (aItem->Frame() == aFrame) { - mReferenceFrame = aItem->ReferenceFrame(); - mToReferenceFrame = aItem->ToReferenceFrame(); - } + return; } - mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame; + + // See the previous nsDisplayWrapList constructor + if (aItem->Frame() == aFrame) { + mReferenceFrame = aItem->ReferenceFrame(); + mToReferenceFrame = aItem->ToReferenceFrame(); + } +} + +nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, nsDisplayItem* aItem, + const nsIFrame* aReferenceFrame, + const nsPoint& aToReferenceFrame) + : nsDisplayItem(aBuilder, aFrame, aReferenceFrame, aToReferenceFrame) + , mOverrideZIndex(0) +{ + mList.AppendToTop(aItem); + mBounds = mList.GetBounds(aBuilder); } nsDisplayWrapList::~nsDisplayWrapList() { mList.DeleteAll(); - - MOZ_COUNT_DTOR(nsDisplayWrapList); } void @@ -2956,7 +3094,8 @@ nsDisplayWrapList::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { bool nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { // Convert the passed in visible region to our appunits. nsRegion visibleRegion; // mVisibleRect has been clipped to GetClippedBounds @@ -2965,7 +3104,8 @@ nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder, bool retval = mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, - mVisibleRect); + mVisibleRect, + aAllowVisibleRegionExpansion); nsRegion removed; // removed = originalVisibleRegion - visibleRegion @@ -2994,6 +3134,13 @@ bool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColo return false; } +bool nsDisplayWrapList::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame) { + NS_WARNING("nsDisplayWrapList::IsVaryingRelativeToMovingFrame called unexpectedly"); + // We could try to do something but let's conservatively just return true. + return true; +} + void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { NS_ERROR("nsDisplayWrapList should have been flattened away for painting"); @@ -3154,7 +3301,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder, return nullptr; } nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, aContainerParameters, nullptr); if (!container) return nullptr; @@ -3238,7 +3385,8 @@ nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder, bool nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { // Our children are translucent so we should not allow them to subtract // area from aVisibleRegion. We do need to find out what is visible under // our children in the temporary compositing buffer, because if our children @@ -3247,8 +3395,10 @@ nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder, nsRect bounds = GetClippedBounds(aBuilder); nsRegion visibleUnderChildren; visibleUnderChildren.And(*aVisibleRegion, bounds); + nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion); return - nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren); + nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren, + allowExpansion); } bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { @@ -3314,7 +3464,7 @@ nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder, newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, newContainerParameters, nullptr); if (!container) { return nullptr; @@ -3326,7 +3476,8 @@ nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder, } bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { // Our children are need their backdrop so we should not allow them to subtract // area from aVisibleRegion. We do need to find out what is visible under // our children in the temporary compositing buffer, because if our children @@ -3335,7 +3486,10 @@ bool nsDisplayMixBlendMode::ComputeVisibility(nsDisplayListBuilder* aBuilder, nsRect bounds = GetClippedBounds(aBuilder); nsRegion visibleUnderChildren; visibleUnderChildren.And(*aVisibleRegion, bounds); - return nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren); + nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion); + return + nsDisplayWrapList::ComputeVisibility(aBuilder, &visibleUnderChildren, + allowExpansion); } bool nsDisplayMixBlendMode::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { @@ -3387,7 +3541,7 @@ nsDisplayBlendContainer::BuildLayer(nsDisplayListBuilder* aBuilder, newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true; nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, newContainerParameters, nullptr); if (!container) { return nullptr; @@ -3432,7 +3586,7 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aContainerParameters) { nsRefPtr layer = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, aContainerParameters, nullptr); if (mFlags & VERTICAL_SCROLLBAR) { layer->SetScrollbarData(mScrollTarget, Layer::ScrollDirection::VERTICAL); @@ -3485,7 +3639,7 @@ nsDisplaySubDocument::BuildLayer(nsDisplayListBuilder* aBuilder, container->SetScrollHandoffParentId(mScrollParentId); RecordFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(), - container, viewport, + container, mList.GetVisibleRect(), viewport, false, isRootContentDocument, aContainerParameters); } @@ -3508,14 +3662,16 @@ nsDisplaySubDocument::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) bool nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { nsRect displayport; bool usingDisplayPort = nsLayoutUtils::ViewportHasDisplayPort(mFrame->PresContext(), &displayport); if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) { - return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion); + return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion); } nsRegion childVisibleRegion; @@ -3526,8 +3682,9 @@ nsDisplaySubDocument::ComputeVisibility(nsDisplayListBuilder* aBuilder, nsRect boundedRect = childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder)); + nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion); bool visible = mList.ComputeVisibilityForSublist( - aBuilder, &childVisibleRegion, boundedRect, + aBuilder, &childVisibleRegion, boundedRect, allowExpansion, usingDisplayPort ? mFrame : nullptr); // We don't allow this computation to influence aVisibleRegion, on the // assumption that the layer can be asynchronously scrolled so we'll @@ -3685,7 +3842,6 @@ nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, , mScrollFrame(aScrollFrame) , mScrolledFrame(aScrolledFrame) , mScrollParentId(aBuilder->GetCurrentScrollParentId()) - , mDisplayPortContentsOpaque(false) { #ifdef NS_BUILD_REFCNT_LOGGING MOZ_COUNT_CTOR(nsDisplayScrollLayer); @@ -3704,7 +3860,6 @@ nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, , mScrollFrame(aScrollFrame) , mScrolledFrame(aScrolledFrame) , mScrollParentId(aBuilder->GetCurrentScrollParentId()) - , mDisplayPortContentsOpaque(false) { #ifdef NS_BUILD_REFCNT_LOGGING MOZ_COUNT_CTOR(nsDisplayScrollLayer); @@ -3722,7 +3877,6 @@ nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder, , mScrollFrame(aScrollFrame) , mScrolledFrame(aScrolledFrame) , mScrollParentId(aBuilder->GetCurrentScrollParentId()) - , mDisplayPortContentsOpaque(false) { #ifdef NS_BUILD_REFCNT_LOGGING MOZ_COUNT_CTOR(nsDisplayScrollLayer); @@ -3750,28 +3904,12 @@ nsDisplayScrollLayer::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) return nsDisplayWrapList::GetBounds(aBuilder, aSnap); } -nsRect -nsDisplayScrollLayer::GetScrolledContentRectToDraw(nsDisplayListBuilder* aBuilder, - nsRect* aDisplayPort) -{ - if (aDisplayPort) { - // The visible region for the children may be much bigger than the hole we - // are viewing the children from, so that the compositor process has enough - // content to asynchronously pan while content is being refreshed. - // XXX mScrollFrame seems wrong here; we should add the offset of the - // scrollport - return *aDisplayPort + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame()); - } - bool snap; - return GetBounds(aBuilder, &snap); -} - already_AddRefed nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aContainerParameters) { nsRefPtr layer = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, aContainerParameters, nullptr); nsRect viewport = mScrollFrame->GetRect() - @@ -3780,28 +3918,12 @@ nsDisplayScrollLayer::BuildLayer(nsDisplayListBuilder* aBuilder, layer->SetScrollHandoffParentId(mScrollParentId); RecordFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), layer, - viewport, false, false, aContainerParameters); - - if (mList.IsOpaque()) { - nsRect displayport; - bool usingDisplayport = - nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport); - mDisplayPortContentsOpaque = mList.GetBounds(aBuilder).Contains( - GetScrolledContentRectToDraw(aBuilder, usingDisplayport ? &displayport : nullptr)); - } else { - mDisplayPortContentsOpaque = false; - } + mList.GetVisibleRect(), viewport, + false, false, aContainerParameters); return layer.forget(); } -bool -nsDisplayScrollLayer::IsConstructingScrollLayerForScrolledFrame(const nsIFrame* aScrolledFrame) -{ - FrameProperties props = aScrolledFrame->Properties(); - return reinterpret_cast(props.Get(nsIFrame::ScrollLayerCount())) != 0; -} - bool nsDisplayScrollLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) { @@ -3814,18 +3936,28 @@ nsDisplayScrollLayer::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBui bool nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { nsRect displayport; bool usingDisplayPort = nsLayoutUtils::GetDisplayPort(mScrolledFrame->GetContent(), &displayport); - nsRect scrolledContentRect = GetScrolledContentRectToDraw(aBuilder, - usingDisplayPort ? &displayport : nullptr); + nsRegion childVisibleRegion; + if (usingDisplayPort) { + // The visible region for the children may be much bigger than the hole we + // are viewing the children from, so that the compositor process has enough + // content to asynchronously pan while content is being refreshed. + childVisibleRegion = displayport + mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame()); + } else { + bool snap; + childVisibleRegion = GetBounds(aBuilder, &snap); + } - nsRect boundedRect = scrolledContentRect.Intersect(mList.GetBounds(aBuilder)); - nsRegion childVisibleRegion = scrolledContentRect; + nsRect boundedRect = + childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder)); + nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion); bool visible = mList.ComputeVisibilityForSublist( - aBuilder, &childVisibleRegion, boundedRect, + aBuilder, &childVisibleRegion, boundedRect, allowExpansion, usingDisplayPort ? mScrollFrame : nullptr); // We don't allow this computation to influence aVisibleRegion, on the // assumption that the layer can be asynchronously scrolled so we'll @@ -4003,6 +4135,8 @@ nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer( nsDisplayScrollInfoLayer::~nsDisplayScrollInfoLayer() { + FrameProperties props = mScrolledFrame->Properties(); + props.Remove(nsIFrame::ScrollLayerCount()); MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer); } @@ -4083,7 +4217,8 @@ void nsDisplayZoom::Paint(nsDisplayListBuilder* aBuilder, } bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder, - nsRegion *aVisibleRegion) + nsRegion *aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { // Convert the passed in visible region to our appunits. nsRegion visibleRegion; @@ -4094,6 +4229,8 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder, nsRect transformedVisibleRect = mVisibleRect.ConvertAppUnitsRoundOut(mParentAPD, mAPD); + nsRect allowExpansion = + aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD); bool retval; // If we are to generate a scrollable layer we call // nsDisplaySubDocument::ComputeVisibility to make the necessary adjustments @@ -4103,10 +4240,12 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder, if (!(mFlags & GENERATE_SCROLLABLE_LAYER) || !usingDisplayPort) { retval = mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, - transformedVisibleRect); + transformedVisibleRect, + allowExpansion); } else { retval = - nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion); + nsDisplaySubDocument::ComputeVisibility(aBuilder, &visibleRegion, + allowExpansion); } nsRegion removed; @@ -4193,15 +4332,12 @@ nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame) #endif -nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, - nsIFrame *aFrame, nsDisplayList *aList, - const nsRect& aChildrenVisibleRect, - ComputeTransformFunction aTransformGetter, +nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, + nsDisplayList *aList, ComputeTransformFunction aTransformGetter, uint32_t aIndex) : nsDisplayItem(aBuilder, aFrame) , mStoredList(aBuilder, aFrame, aList) , mTransformGetter(aTransformGetter) - , mChildrenVisibleRect(aChildrenVisibleRect) , mIndex(aIndex) { MOZ_COUNT_CTOR(nsDisplayTransform); @@ -4210,44 +4346,33 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); } -void -nsDisplayTransform::SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder) -{ - mReferenceFrame = - aBuilder->FindReferenceFrameFor(GetTransformRootFrame(mFrame)); - mToReferenceFrame = mFrame->GetOffsetToCrossDoc(mReferenceFrame); - mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame; -} - -nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, - nsIFrame *aFrame, nsDisplayList *aList, - const nsRect& aChildrenVisibleRect, - uint32_t aIndex) +nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, + nsDisplayList *aList, uint32_t aIndex) : nsDisplayItem(aBuilder, aFrame) , mStoredList(aBuilder, aFrame, aList) , mTransformGetter(nullptr) - , mChildrenVisibleRect(aChildrenVisibleRect) , mIndex(aIndex) { MOZ_COUNT_CTOR(nsDisplayTransform); NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); - SetReferenceFrameToAncestor(aBuilder); + mReferenceFrame = + aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); + mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); } -nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, - nsIFrame *aFrame, nsDisplayItem *aItem, - const nsRect& aChildrenVisibleRect, - uint32_t aIndex) +nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, + nsDisplayItem *aItem, uint32_t aIndex) : nsDisplayItem(aBuilder, aFrame) , mStoredList(aBuilder, aFrame, aItem) , mTransformGetter(nullptr) - , mChildrenVisibleRect(aChildrenVisibleRect) , mIndex(aIndex) { MOZ_COUNT_CTOR(nsDisplayTransform); NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); - SetReferenceFrameToAncestor(aBuilder); + mReferenceFrame = + aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); + mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); } @@ -4682,11 +4807,10 @@ already_AddRefed nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu return nullptr; } - bool prerender = ShouldPrerenderTransformedContent(aBuilder, mFrame, false); - uint32_t flags = prerender ? + uint32_t flags = ShouldPrerenderTransformedContent(aBuilder, mFrame, false) ? FrameLayerBuilder::CONTAINER_NOT_CLIPPED_BY_ANCESTORS : 0; nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mStoredList.GetChildren(), + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetChildren(), aContainerParameters, &newTransformMatrix, flags); if (!container) { @@ -4704,7 +4828,7 @@ already_AddRefed nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder, this, mFrame, eCSSProperty_transform); - if (prerender) { + if (ShouldPrerenderTransformedContent(aBuilder, mFrame, false)) { container->SetUserData(nsIFrame::LayerIsPrerenderedDataKey(), /*the value is irrelevant*/nullptr); container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_MAY_CHANGE_TRANSFORM); @@ -4750,7 +4874,8 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder, } bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder, - nsRegion *aVisibleRegion) + nsRegion *aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { /* As we do this, we need to be sure to * untransform the visible rect, since we want everything that's painting to @@ -4936,7 +5061,7 @@ nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder, if (matrix.Is2D(&matrix2d) && matrix2d.PreservesAxisAlignedRectangles() && mStoredList.GetOpaqueRegion(aBuilder, &tmpSnap).Contains(untransformedVisible)) { - result = mVisibleRect.Intersect(GetBounds(aBuilder, &tmpSnap)); + result = mVisibleRect; } return result; } @@ -4996,7 +5121,7 @@ nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder, /* Now, move everything over to this frame and signal that * we merged things! */ - mStoredList.MergeFromTrackingMergedFrames(&static_cast(aItem)->mStoredList); + mStoredList.MergeFrom(&static_cast(aItem)->mStoredList); return true; } @@ -5209,14 +5334,15 @@ nsDisplaySVGEffects::BuildLayer(nsDisplayListBuilder* aBuilder, } nsRefPtr container = aManager->GetLayerBuilder()-> - BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList, + BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, newContainerParameters, nullptr); return container.forget(); } bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { nsPoint offset = ToReferenceFrame(); nsRect dirtyRect = nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(mFrame, @@ -5227,7 +5353,7 @@ bool nsDisplaySVGEffects::ComputeVisibility(nsDisplayListBuilder* aBuilder, // not allow them to subtract area from aVisibleRegion. nsRegion childrenVisible(dirtyRect); nsRect r = dirtyRect.Intersect(mList.GetBounds(aBuilder)); - mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r); + mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect()); return true; } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index dcf85e71c80..0aceef8da4e 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -201,27 +201,23 @@ public: * @return the root of given frame's (sub)tree, whose origin * establishes the coordinate system for the child display items. */ - const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame, - nsPoint* aOffset = nullptr) + const nsIFrame* FindReferenceFrameFor(const nsIFrame *aFrame) { - if (aFrame == mCurrentFrame) { - if (aOffset) { - *aOffset = mCurrentOffsetToReferenceFrame; - } - return mCurrentReferenceFrame; + if (aFrame == mCachedOffsetFrame) { + return mCachedReferenceFrame; } for (const nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) { if (f == mReferenceFrame || f->IsTransformed()) { - if (aOffset) { - *aOffset = aFrame->GetOffsetToCrossDoc(f); - } + mCachedOffsetFrame = aFrame; + mCachedReferenceFrame = f; + mCachedOffset = aFrame->GetOffsetToCrossDoc(f); return f; } } - if (aOffset) { - *aOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame); - } + mCachedOffsetFrame = aFrame; + mCachedReferenceFrame = mReferenceFrame; + mCachedOffset = aFrame->GetOffsetToCrossDoc(mReferenceFrame); return mReferenceFrame; } @@ -238,12 +234,14 @@ public: * @return a point pt such that adding pt to a coordinate relative to aFrame * makes it relative to ReferenceFrame(), i.e., returns * aFrame->GetOffsetToCrossDoc(ReferenceFrame()). The returned point is in - * the appunits of aFrame. + * the appunits of aFrame. It may be optimized to be faster than + * aFrame->GetOffsetToCrossDoc(ReferenceFrame()) (but currently isn't). */ - const nsPoint ToReferenceFrame(const nsIFrame* aFrame) { - nsPoint result; - FindReferenceFrameFor(aFrame, &result); - return result; + const nsPoint& ToReferenceFrame(const nsIFrame* aFrame) { + if (aFrame != mCachedOffsetFrame) { + FindReferenceFrameFor(aFrame); + } + return mCachedOffset; } /** * When building the display list, the scrollframe aFrame will be "ignored" @@ -313,14 +311,6 @@ public: void SetDescendIntoSubdocuments(bool aDescend) { mDescendIntoSubdocuments = aDescend; } bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; } - /** - * Get dirty rect relative to current frame (the frame that we're calling - * BuildDisplayList on right now). - */ - const nsRect& GetDirtyRect() { return mDirtyRect; } - const nsIFrame* GetCurrentFrame() { return mCurrentFrame; } - const nsIFrame* GetCurrentReferenceFrame() { return mCurrentReferenceFrame; } - /** * Returns true if merging and flattening of display lists should be * performed while computing visibility. @@ -406,6 +396,12 @@ public: */ void SetInTransform(bool aInTransform) { mInTransform = aInTransform; } + /** + * Returns true if we're currently building display items that are in + * true fixed position subtree. + */ + bool IsInFixedPos() const { return mInFixedPos; } + /** * @return true if images have been set to decode synchronously. */ @@ -454,6 +450,19 @@ public: */ void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect); + /** + * Get the area of the final transparent region. + */ + const nsRegion* GetFinalTransparentRegion() { return mFinalTransparentRegion; } + /** + * Record the area of the final transparent region after all visibility + * calculations were performed. + */ + void SetFinalTransparentRegion(const nsRegion& aFinalTransparentRegion) + { + mFinalTransparentRegion = &aFinalTransparentRegion; + } + const nsTArray& GetThemeGeometries() { return mThemeGeometries; } /** @@ -517,58 +526,59 @@ public: /** * A helper class to temporarily set the value of * mIsAtRootOfPseudoStackingContext, and temporarily - * set mCurrentFrame and related state. Also temporarily sets mDirtyRect. - * aDirtyRect is relative to aForChild. + * update mCachedOffsetFrame/mCachedOffset from a frame to its child. + * Also saves and restores mClipState. */ class AutoBuildingDisplayList; friend class AutoBuildingDisplayList; class AutoBuildingDisplayList { public: - AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, - nsIFrame* aForChild, - const nsRect& aDirtyRect, bool aIsRoot) + AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, bool aIsRoot) : mBuilder(aBuilder), - mPrevFrame(aBuilder->mCurrentFrame), - mPrevReferenceFrame(aBuilder->mCurrentReferenceFrame), + mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame), + mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame), mPrevLayerEventRegions(aBuilder->mLayerEventRegions), - mPrevOffset(aBuilder->mCurrentOffsetToReferenceFrame), - mPrevDirtyRect(aBuilder->mDirtyRect), + mPrevCachedOffset(aBuilder->mCachedOffset), + mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext), + mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler) + { + aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot; + } + AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, + nsIFrame* aForChild, bool aIsRoot) + : mBuilder(aBuilder), + mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame), + mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame), + mPrevLayerEventRegions(aBuilder->mLayerEventRegions), + mPrevCachedOffset(aBuilder->mCachedOffset), mPrevIsAtRootOfPseudoStackingContext(aBuilder->mIsAtRootOfPseudoStackingContext), mPrevAncestorHasTouchEventHandler(aBuilder->mAncestorHasTouchEventHandler) { if (aForChild->IsTransformed()) { - aBuilder->mCurrentOffsetToReferenceFrame = nsPoint(); - aBuilder->mCurrentReferenceFrame = aForChild; - } else if (aBuilder->mCurrentFrame == aForChild->GetParent()) { - aBuilder->mCurrentOffsetToReferenceFrame += aForChild->GetPosition(); + aBuilder->mCachedOffset = nsPoint(); + aBuilder->mCachedReferenceFrame = aForChild; + } else if (mPrevCachedOffsetFrame == aForChild->GetParent()) { + aBuilder->mCachedOffset += aForChild->GetPosition(); } else { - aBuilder->mCurrentReferenceFrame = - aBuilder->FindReferenceFrameFor(aForChild, - &aBuilder->mCurrentOffsetToReferenceFrame); + aBuilder->mCachedOffset = aBuilder->ToReferenceFrame(aForChild); } - aBuilder->mCurrentFrame = aForChild; - aBuilder->mDirtyRect = aDirtyRect; + aBuilder->mCachedOffsetFrame = aForChild; aBuilder->mIsAtRootOfPseudoStackingContext = aIsRoot; } - void SetDirtyRect(const nsRect& aRect) { - mBuilder->mDirtyRect = aRect; - } ~AutoBuildingDisplayList() { - mBuilder->mCurrentFrame = mPrevFrame; - mBuilder->mCurrentReferenceFrame = mPrevReferenceFrame; + mBuilder->mCachedOffsetFrame = mPrevCachedOffsetFrame; + mBuilder->mCachedReferenceFrame = mPrevCachedReferenceFrame; mBuilder->mLayerEventRegions = mPrevLayerEventRegions; - mBuilder->mCurrentOffsetToReferenceFrame = mPrevOffset; - mBuilder->mDirtyRect = mPrevDirtyRect; + mBuilder->mCachedOffset = mPrevCachedOffset; mBuilder->mIsAtRootOfPseudoStackingContext = mPrevIsAtRootOfPseudoStackingContext; mBuilder->mAncestorHasTouchEventHandler = mPrevAncestorHasTouchEventHandler; } private: nsDisplayListBuilder* mBuilder; - const nsIFrame* mPrevFrame; - const nsIFrame* mPrevReferenceFrame; + const nsIFrame* mPrevCachedOffsetFrame; + const nsIFrame* mPrevCachedReferenceFrame; nsDisplayLayerEventRegions* mPrevLayerEventRegions; - nsPoint mPrevOffset; - nsRect mPrevDirtyRect; + nsPoint mPrevCachedOffset; bool mPrevIsAtRootOfPseudoStackingContext; bool mPrevAncestorHasTouchEventHandler; }; @@ -592,6 +602,25 @@ public: bool mOldValue; }; + /** + * A helper class to temporarily set the value of mInFixedPos. + */ + class AutoInFixedPosSetter; + friend class AutoInFixedPosSetter; + class AutoInFixedPosSetter { + public: + AutoInFixedPosSetter(nsDisplayListBuilder* aBuilder, bool aInFixedPos) + : mBuilder(aBuilder), mOldValue(aBuilder->mInFixedPos) { + aBuilder->mInFixedPos = aInFixedPos; + } + ~AutoInFixedPosSetter() { + mBuilder->mInFixedPos = mOldValue; + } + private: + nsDisplayListBuilder* mBuilder; + bool mOldValue; + }; + /** * A helper class to temporarily set the value of mCurrentScrollParentId. */ @@ -667,15 +696,11 @@ public: * -moz-win-exclude-glass style. Used in setting glass margins on * Windows. */ - void AddWindowOpaqueRegion(const nsRegion& bounds) { - mWindowOpaqueRegion.Or(mWindowOpaqueRegion, bounds); + void AddExcludedGlassRegion(nsRect &bounds) { + mExcludedGlassRegion.Or(mExcludedGlassRegion, bounds); } - /** - * Returns the window opaque region built so far. This may be incomplete - * since the opaque region is built during layer construction. - */ - const nsRegion& GetWindowOpaqueRegion() { - return mWindowOpaqueRegion; + const nsRegion& GetExcludedGlassRegion() { + return mExcludedGlassRegion; } void SetGlassDisplayItem(nsDisplayItem* aItem) { if (mGlassDisplayItem) { @@ -718,7 +743,6 @@ private: struct PresShellState { nsIPresShell* mPresShell; nsIFrame* mCaretFrame; - nsRect mPrevDirtyRect; uint32_t mFirstFrameMarkedForDisplay; bool mIsBackgroundOnly; }; @@ -738,16 +762,13 @@ private: nsAutoTArray mThemeGeometries; nsDisplayTableItem* mCurrentTableItem; DisplayListClipState mClipState; - // mCurrentFrame is the frame that we're currently calling (or about to call) - // BuildDisplayList on. - const nsIFrame* mCurrentFrame; - // The reference frame for mCurrentFrame. - const nsIFrame* mCurrentReferenceFrame; - // The offset from mCurrentFrame to mCurrentReferenceFrame. - nsPoint mCurrentOffsetToReferenceFrame; - // Relative to mCurrentFrame. - nsRect mDirtyRect; - nsRegion mWindowOpaqueRegion; + const nsRegion* mFinalTransparentRegion; + // When mCachedOffsetFrame is non-null, mCachedOffset is the offset from + // mCachedOffsetFrame to mReferenceFrame. + const nsIFrame* mCachedOffsetFrame; + const nsIFrame* mCachedReferenceFrame; + nsPoint mCachedOffset; + nsRegion mExcludedGlassRegion; // The display item for the Windows window glass background, if any nsDisplayItem* mGlassDisplayItem; nsTArray mDisplayItemClipsToDestroy; @@ -769,6 +790,7 @@ private: // True when we're building a display list that's directly or indirectly // under an nsDisplayTransform bool mInTransform; + bool mInFixedPos; bool mSyncDecodeImages; bool mIsPaintingToWindow; bool mIsCompositingCheap; @@ -826,14 +848,26 @@ public: nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : mFrame(aFrame) , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder)) + , mInFixedPos(aBuilder->IsInFixedPos()) +#ifdef MOZ_DUMP_PAINTING + , mPainted(false) +#endif + { + mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame); + mToReferenceFrame = aBuilder->ToReferenceFrame(aFrame); + } + nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + const nsIFrame* aReferenceFrame, + const nsPoint& aToReferenceFrame) + : mFrame(aFrame) + , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder)) + , mReferenceFrame(aReferenceFrame) + , mToReferenceFrame(aToReferenceFrame) + , mInFixedPos(aBuilder->IsInFixedPos()) #ifdef MOZ_DUMP_PAINTING , mPainted(false) #endif { - mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame); - NS_ASSERTION(aBuilder->GetDirtyRect().width >= 0 || - !aBuilder->IsForPainting(), "dirty rect not set"); - mVisibleRect = aBuilder->GetDirtyRect() + mToReferenceFrame; } /** * This constructor is only used in rare cases when we need to construct @@ -843,13 +877,14 @@ public: : mFrame(aFrame) , mClip(nullptr) , mReferenceFrame(nullptr) + , mInFixedPos(false) #ifdef MOZ_DUMP_PAINTING , mPainted(false) #endif { } virtual ~nsDisplayItem() {} - + void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) CPP_THROW_NEW { return aBuilder->Allocate(aSize); @@ -1059,7 +1094,7 @@ public: * @param aSnap set to true if the edges of the rectangles of the opaque * region would be snapped to device pixels when drawing * @return a region of the item that is opaque --- that is, every pixel - * that is visible is painted with an opaque + * that is visible (according to ComputeVisibility) is painted with an opaque * color. This is useful for determining when one piece * of content completely obscures another so that we can do occlusion * culling. @@ -1077,6 +1112,16 @@ public: * bounds with the same (possibly translucent) color */ virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { return false; } + /** + * @return false if the painting performed by the item is invariant + * when the item's underlying frame is moved relative to aFrame. + * In other words, if you render the item at locations P and P', the rendering + * only differs by the translation. + * It return true for all wrapped lists. + */ + virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame) + { return false; } /** * @return true if the contents of this item are rendered fixed relative * to the nearest viewport. @@ -1188,7 +1233,8 @@ public: * is visible. */ virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion); + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion); /** * Try to merge with the other item (which is below us in the display @@ -1235,17 +1281,10 @@ public: virtual nsDisplayList* GetChildren() { return nullptr; } /** - * Returns the visible rect. + * Returns the visible rect. Should only be called after ComputeVisibility + * has happened. */ - const nsRect& GetVisibleRect() const { return mVisibleRect; } - - /** - * Returns the visible rect for the children, relative to their - * reference frame. Can be different from mVisibleRect for nsDisplayTransform, - * since the reference frame for the children is different from the reference - * frame for the item itself. - */ - virtual const nsRect& GetVisibleRectForChildren() const { return mVisibleRect; } + const nsRect& GetVisibleRect() { return mVisibleRect; } /** * Stores the given opacity value to be applied when drawing. Returns @@ -1276,7 +1315,7 @@ public: * -- Subtracts bounds from aVisibleRegion if the item is opaque */ bool RecomputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion); + nsRegion* aVisibleRegion); /** * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame()) @@ -1342,6 +1381,13 @@ public: } } + // If we return false here it means that if this item creates a layer then + // ProcessDisplayItems will not set the visible region on the layer. The item + // should set the visible region, usually in BuildContainerLayer. + virtual bool SetVisibleRegionOnLayer() { return true; } + + bool IsInFixedPos() { return mInFixedPos; } + protected: friend class nsDisplayList; @@ -1354,12 +1400,12 @@ protected: // Result of ToReferenceFrame(mFrame), if mFrame is non-null nsPoint mToReferenceFrame; // This is the rectangle that needs to be painted. - // Display item construction sets this to the dirty rect. // nsDisplayList::ComputeVisibility sets this to the visible region // of the item by intersecting the current visible region with the bounds // of the item. Paint implementations can use this to limit their drawing. // Guaranteed to be contained in GetBounds(). nsRect mVisibleRect; + bool mInFixedPos; #ifdef MOZ_DUMP_PAINTING // True if this frame has been painted. bool mPainted; @@ -1390,12 +1436,14 @@ public: /** * Create an empty list. */ - nsDisplayList() - : mIsOpaque(false) - , mForceTransparentSurface(false) + nsDisplayList() : + mIsOpaque(false) { mTop = &mSentinel; mSentinel.mAbove = nullptr; +#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) + mDidComputeVisibility = false; +#endif } ~nsDisplayList() { if (mSentinel.mAbove) { @@ -1561,6 +1609,7 @@ public: bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion, const nsRect& aListVisibleBounds, + const nsRect& aAllowVisibleRegionExpansion, nsIFrame* aDisplayPortFrame = nullptr); /** @@ -1580,13 +1629,16 @@ public: * empty, i.e. everything visible in this list is opaque. */ bool IsOpaque() const { + NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility"); return mIsOpaque; } /** - * Returns true if any display item requires the surface to be transparent. + * Returns true if during ComputeVisibility any display item + * set the surface to be transparent. */ bool NeedsTransparentSurface() const { + NS_ASSERTION(mDidComputeVisibility, "Need to have called ComputeVisibility"); return mForceTransparentSurface; } /** @@ -1626,16 +1678,15 @@ public: PAINT_COMPRESSED = 0x10 }; void PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, - uint32_t aFlags); + uint32_t aFlags) const; /** * Like PaintRoot, but used for internal display sublists. * aForFrame is the frame that the list is associated with. */ void PaintForFrame(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx, - nsIFrame* aForFrame, uint32_t aFlags); + nsIFrame* aForFrame, uint32_t aFlags) const; /** * Get the bounds. Takes the union of the bounds of all children. - * The result is not cached. */ nsRect GetBounds(nsDisplayListBuilder* aBuilder) const; /** @@ -1645,38 +1696,36 @@ public: void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, nsDisplayItem::HitTestState* aState, nsTArray *aOutFrames) const; - /** - * Compute the union of the visible rects of the items in the list. The - * result is not cached. - */ - nsRect GetVisibleRect() const; - void SetIsOpaque() - { - mIsOpaque = true; - } - void SetNeedsTransparentSurface() - { - mForceTransparentSurface = true; - } +#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) + bool DidComputeVisibility() const { return mDidComputeVisibility; } +#endif + + nsRect GetVisibleRect() const { return mVisibleRect; } private: // This class is only used on stack, so we don't have to worry about leaking // it. Don't let us be heap-allocated! void* operator new(size_t sz) CPP_THROW_NEW; + // Utility function used to massage the list during ComputeVisibility. + void FlattenTo(nsTArray* aElements); + nsDisplayItemLink mSentinel; nsDisplayItemLink* mTop; // This is set by ComputeVisibility nsRect mVisibleRect; - // This is set to true by FrameLayerBuilder if the final visible region + // This is set to true by ComputeVisibility if the final visible region // is empty (i.e. everything that was visible is covered by some // opaque content in this list). bool mIsOpaque; - // This is set to true by FrameLayerBuilder if any display item in this + // This is set to true by ComputeVisibility if any display item in this // list needs to force the surface containing this list to be transparent. bool mForceTransparentSurface; +#if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) + bool mDidComputeVisibility; +#endif }; /** @@ -2140,9 +2189,12 @@ public: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; + virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame) MOZ_OVERRIDE; virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE; /** * GetBounds() returns the background painting area. @@ -2344,7 +2396,8 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; virtual bool IsInvisibleInRect(const nsRect& aRect) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER) virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, @@ -2387,7 +2440,8 @@ public: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER) virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE @@ -2528,6 +2582,9 @@ private: * detect and handle this case. */ class nsDisplayWrapList : public nsDisplayItem { + // This is never instantiated directly, so no need to count constructors and + // destructors. + public: /** * Takes all the items from aList and puts them in our list. @@ -2536,11 +2593,10 @@ public: nsDisplayList* aList); nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayItem* aItem); + nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + nsDisplayItem* aItem, const nsIFrame* aReferenceFrame, const nsPoint& aToReferenceFrame); nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) - : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0) - { - MOZ_COUNT_CTOR(nsDisplayWrapList); - } + : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0) {} virtual ~nsDisplayWrapList(); /** * Call this if the wrapped list is changed. @@ -2555,19 +2611,20 @@ public: virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE; + virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame) MOZ_OVERRIDE; virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE { + NS_WARNING("This list should already have been flattened!!!"); return false; } virtual void GetMergedFrames(nsTArray* aFrames) MOZ_OVERRIDE { aFrames->AppendElements(mMergedFrames); } - virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) { - return true; - } virtual bool IsInvalid(nsRect& aRect) MOZ_OVERRIDE { if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) { @@ -2623,11 +2680,14 @@ public: protected: nsDisplayWrapList() {} - void MergeFromTrackingMergedFrames(nsDisplayWrapList* aOther) + void MergeFrom(nsDisplayWrapList* aOther) { mList.AppendToBottom(&aOther->mList); mBounds.UnionRect(mBounds, aOther->mBounds); - mVisibleRect.UnionRect(mVisibleRect, aOther->mVisibleRect); + } + void MergeFromTrackingMergedFrames(nsDisplayWrapList* aOther) + { + MergeFrom(aOther); mMergedFrames.AppendElement(aOther->mFrame); mMergedFrames.MoveElementsFrom(aOther->mMergedFrames); } @@ -2688,7 +2748,8 @@ public: LayerManager* aManager, const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, const nsDisplayItemGeometry* aGeometry, @@ -2736,11 +2797,9 @@ public: LayerManager* aManager, const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; - virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { - return false; - } NS_DISPLAY_DECL_NAME("MixBlendMode", TYPE_MIX_BLEND_MODE) }; @@ -2768,9 +2827,6 @@ public: return mozilla::LAYER_INACTIVE; } virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; - virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { - return false; - } NS_DISPLAY_DECL_NAME("BlendContainer", TYPE_BLEND_CONTAINER) private: @@ -2830,9 +2886,6 @@ public: // Don't allow merging, each sublist must have its own layer return false; } - virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { - return false; - } uint32_t GetFlags() { return mFlags; } NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER) protected: @@ -2860,7 +2913,10 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; + + virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return !(mFlags & GENERATE_SCROLLABLE_LAYER); } virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; @@ -2919,7 +2975,7 @@ public: /** * This potentially creates a layer for the given list of items, whose * visibility is determined by the displayport for the given frame instead of - * normal visibility computation. + * what is passed in to ComputeVisibility. * * Here in content, we can use this to render more content than is actually * visible. Then, the compositing process can manipulate the generated layer @@ -2977,7 +3033,8 @@ public: } virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, @@ -2993,25 +3050,19 @@ public: // after merging, all the nsDisplayScrollLayers should flatten away. intptr_t GetScrollLayerCount(); - static bool IsConstructingScrollLayerForScrolledFrame(const nsIFrame* aScrolledFrame); - virtual nsIFrame* GetScrollFrame() { return mScrollFrame; } virtual nsIFrame* GetScrolledFrame() { return mScrolledFrame; } + virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return false; } + #ifdef MOZ_DUMP_PAINTING virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; #endif - bool IsDisplayPortOpaque() { return mDisplayPortContentsOpaque; } - protected: - nsRect GetScrolledContentRectToDraw(nsDisplayListBuilder* aBuilder, - nsRect* aDisplayPort); - nsIFrame* mScrollFrame; nsIFrame* mScrolledFrame; ViewID mScrollParentId; - bool mDisplayPortContentsOpaque; }; /** @@ -3076,7 +3127,8 @@ public: virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, LayerManager* aManager, const ContainerLayerParameters& aParameters) MOZ_OVERRIDE @@ -3117,12 +3169,10 @@ public: return mEffectsBounds + ToReferenceFrame(); } virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; - virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { - return false; - } NS_DISPLAY_DECL_NAME("SVGEffects", TYPE_SVG_EFFECTS) virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, @@ -3182,14 +3232,11 @@ public: * ferries the underlying frame to the nsDisplayItem constructor. */ nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, - nsDisplayList *aList, const nsRect& aChildrenVisibleRect, - uint32_t aIndex = 0); + nsDisplayList *aList, uint32_t aIndex = 0); nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, - nsDisplayItem *aItem, const nsRect& aChildrenVisibleRect, - uint32_t aIndex = 0); + nsDisplayItem *aItem, uint32_t aIndex = 0); nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, - nsDisplayList *aList, const nsRect& aChildrenVisibleRect, - ComputeTransformFunction aTransformGetter, uint32_t aIndex = 0); + nsDisplayList *aList, ComputeTransformFunction aTransformGetter, uint32_t aIndex = 0); #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayTransform() @@ -3224,7 +3271,8 @@ public: const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder, - nsRegion *aVisibleRegion) MOZ_OVERRIDE; + nsRegion *aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; virtual bool TryMerge(nsDisplayListBuilder *aBuilder, nsDisplayItem *aItem) MOZ_OVERRIDE; virtual uint32_t GetPerFrameKey() MOZ_OVERRIDE { return (mIndex << nsDisplayItem::TYPE_BITS) | nsDisplayItem::GetPerFrameKey(); } @@ -3246,11 +3294,6 @@ public: return nsDisplayItem::ReferenceFrameForChildren(); } - virtual const nsRect& GetVisibleRectForChildren() const MOZ_OVERRIDE - { - return mChildrenVisibleRect; - } - enum { INDEX_MAX = UINT32_MAX >> nsDisplayItem::TYPE_BITS }; @@ -3380,12 +3423,12 @@ public: bool aLogAnimations = false); bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; + virtual bool SetVisibleRegionOnLayer() MOZ_OVERRIDE { return false; } + #ifdef MOZ_DUMP_PAINTING virtual void WriteDebugInfo(nsACString& aTo) MOZ_OVERRIDE; #endif private: - void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder); - static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties, const nsPoint& aOrigin, float aAppUnitsPerPixel, @@ -3396,7 +3439,6 @@ private: nsDisplayWrapList mStoredList; gfx3DMatrix mTransform; ComputeTransformFunction mTransformGetter; - nsRect mChildrenVisibleRect; uint32_t mIndex; }; diff --git a/layout/base/nsLayoutDebugger.cpp b/layout/base/nsLayoutDebugger.cpp index 1096ef4cca8..ff7cb9119b8 100644 --- a/layout/base/nsLayoutDebugger.cpp +++ b/layout/base/nsLayoutDebugger.cpp @@ -154,7 +154,10 @@ PrintDisplayItemTo(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsRect component = aItem->GetComponentAlphaBounds(aBuilder); nsDisplayList* list = aItem->GetChildren(); const DisplayItemClip& clip = aItem->GetClip(); - nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &snap); + nsRegion opaque; + if (!list || list->DidComputeVisibility()) { + opaque = aItem->GetOpaqueRegion(aBuilder, &snap); + } if (aDumpHtml && aItem->Painted()) { nsCString string(aItem->Name()); string.Append('-'); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index f6c545f06db..d18465a7561 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1481,7 +1481,7 @@ nsLayoutUtils::GetScrollableFrameFor(const nsIFrame *aScrolledFrame) { nsIFrame *frame = aScrolledFrame->GetParent(); nsIScrollableFrame *sf = do_QueryFrame(frame); - return (sf && sf->GetScrolledFrame() == aScrolledFrame) ? sf : nullptr; + return sf; } /* static */ void @@ -1603,9 +1603,9 @@ IsScrollbarThumbLayerized(nsIFrame* aThumbFrame) return reinterpret_cast(aThumbFrame->Properties().Get(ScrollbarThumbLayerized())); } -nsIFrame* -nsLayoutUtils::GetAnimatedGeometryRootForFrame(nsIFrame* aFrame, - const nsIFrame* aStopAtAncestor) +static nsIFrame* +GetAnimatedGeometryRootForFrame(nsIFrame* aFrame, + const nsIFrame* aStopAtAncestor) { nsIFrame* f = aFrame; nsIFrame* stickyFrame = nullptr; @@ -2323,7 +2323,7 @@ nsLayoutUtils::GetLayerTransformForFrame(nsIFrame* aFrame, false/*don't build caret*/); nsDisplayList list; nsDisplayTransform* item = - new (&builder) nsDisplayTransform(&builder, aFrame, &list, nsRect()); + new (&builder) nsDisplayTransform(&builder, aFrame, &list); *aTransform = item->GetTransform(); @@ -2937,6 +2937,9 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram } #endif + list.ComputeVisibilityForRoot(&builder, &visibleRegion, + usingDisplayPort ? rootScrollFrame : nullptr); + uint32_t flags = nsDisplayList::PAINT_DEFAULT; if (aFlags & PAINT_WIDGET_LAYERS) { flags |= nsDisplayList::PAINT_USE_WIDGET_LAYERS; @@ -2952,6 +2955,7 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram } else if (!(aFlags & PAINT_DOCUMENT_RELATIVE)) { nsIWidget *widget = aFrame->GetNearestWidget(); if (widget) { + builder.SetFinalTransparentRegion(visibleRegion); // If we're finished building display list items for painting of the outermost // pres shell, notify the widget about any toolbars we've encountered. widget->UpdateThemeGeometries(builder.GetThemeGeometries()); @@ -3019,7 +3023,8 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram !(aFlags & PAINT_DOCUMENT_RELATIVE)) { nsIWidget *widget = aFrame->GetNearestWidget(); if (widget) { - nsRegion excludedRegion = builder.GetWindowOpaqueRegion(); + nsRegion excludedRegion = builder.GetExcludedGlassRegion(); + excludedRegion.Sub(excludedRegion, visibleRegion); nsIntRegion windowRegion(excludedRegion.ToNearestPixels(presContext->AppUnitsPerDevPixel())); widget->UpdateOpaqueRegion(windowRegion); } diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 6e65aba22cb..5dce45e63aa 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -499,14 +499,6 @@ public: static nsIFrame* GetAnimatedGeometryRootFor(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); - /** - * Finds the nearest ancestor frame to aFrame that is considered to have (or - * will have) "animated geometry". This could be aFrame. Returns - * aStopAtAncestor if no closer ancestor is found. - */ - static nsIFrame* GetAnimatedGeometryRootForFrame(nsIFrame* aFrame, - const nsIFrame* aStopAtAncestor); - /** * GetScrollableFrameFor returns the scrollable frame for a scrolled frame */ diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index fc3b4bbbf83..19380fc666a 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -5155,6 +5155,7 @@ PresShell::PaintRangePaintInfo(nsTArray >* aItems, aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y); nsRegion visible(aArea); + rangeInfo->mList.ComputeVisibilityForRoot(&rangeInfo->mBuilder, &visible); rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, rc, nsDisplayList::PAINT_DEFAULT); aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y); } diff --git a/layout/forms/nsSelectsAreaFrame.cpp b/layout/forms/nsSelectsAreaFrame.cpp index 006ba401c48..14f33a94a11 100644 --- a/layout/forms/nsSelectsAreaFrame.cpp +++ b/layout/forms/nsSelectsAreaFrame.cpp @@ -37,9 +37,6 @@ public: : nsDisplayWrapList(aBuilder, aFrame, aList) {} virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames); - virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { - return false; - } NS_DISPLAY_DECL_NAME("OptionEventGrabber", TYPE_OPTION_EVENT_GRABBER) }; diff --git a/layout/generic/nsCanvasFrame.h b/layout/generic/nsCanvasFrame.h index b7f17d1231e..66d73d9e5a5 100644 --- a/layout/generic/nsCanvasFrame.h +++ b/layout/generic/nsCanvasFrame.h @@ -155,7 +155,8 @@ public: } virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE { return NS_GET_A(mColor) > 0; } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index cff83393151..2ba8020af72 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1737,9 +1737,7 @@ DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, #endif static nsresult -WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, - nsDisplayList *aList, nsDisplayList *aOutput, - uint32_t& aIndex, nsDisplayList* aTemp) +WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList, nsDisplayList *aOutput, uint32_t& aIndex, nsDisplayList* aTemp) { if (aIndex > nsDisplayTransform::INDEX_MAX) { return NS_OK; @@ -1758,8 +1756,7 @@ WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, switch (item->GetType()) { case nsDisplayItem::TYPE_TRANSFORM: { if (!aTemp->IsEmpty()) { - aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, - aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++)); + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); } // Override item's clipping with our current clip state (if any). Since we're // bubbling up a preserve-3d transformed child to a preserve-3d parent, @@ -1781,8 +1778,7 @@ WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, } case nsDisplayItem::TYPE_OPACITY: { if (!aTemp->IsEmpty()) { - aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, - aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++)); + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); } nsDisplayOpacity *opacity = static_cast(item); nsDisplayList output; @@ -1792,8 +1788,7 @@ WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, rv = WrapPreserve3DListInternal(aFrame, aBuilder, opacity->GetChildren(), &output, aIndex, aTemp); if (!aTemp->IsEmpty()) { - output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, - aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++)); + output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); } opacity->GetChildren()->AppendToTop(&output); opacity->UpdateBounds(aBuilder); @@ -1803,12 +1798,10 @@ WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, default: { if (childFrame->StyleDisplay()->BackfaceIsHidden()) { if (!aTemp->IsEmpty()) { - aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, - aFrame, aTemp, aTemp->GetVisibleRect(), aIndex++)); + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++)); } - aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, - childFrame, item, item->GetVisibleRect(), aIndex++)); + aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item, aIndex++)); } else { aTemp->AppendToTop(item); } @@ -1833,18 +1826,15 @@ IsScrollFrameActive(nsIScrollableFrame* aScrollableFrame) } static nsresult -WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, - nsDisplayList *aList) +WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList) { uint32_t index = 0; nsDisplayList temp; nsDisplayList output; - nsresult rv = WrapPreserve3DListInternal(aFrame, aBuilder, aList, &output, - index, &temp); + nsresult rv = WrapPreserve3DListInternal(aFrame, aBuilder, aList, &output, index, &temp); if (!temp.IsEmpty()) { - output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, - &temp, temp.GetVisibleRect(), index++)); + output.AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, &temp, index++)); } aList->AppendToTop(&output); @@ -1917,8 +1907,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, AutoSaveRestoreBlendMode autoRestoreBlendMode(*aBuilder); aBuilder->SetContainsBlendModes(BlendModeSet()); - nsPoint offsetToReferenceFrame = aBuilder->ToReferenceFrame(this); - if (isTransformed) { const nsRect overflow = GetVisualOverflowRectRelativeToSelf(); if (aBuilder->IsForPainting() && @@ -1929,10 +1917,11 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, return; } - dirtyRect += offsetToReferenceFrame; + nsPoint offset = aBuilder->ToReferenceFrame(this); + dirtyRect += offset; + nsRect untransformedDirtyRect; - if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, - offsetToReferenceFrame, &untransformedDirtyRect)) { + if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) { dirtyRect = untransformedDirtyRect; } else { NS_WARNING("Unable to untransform dirty rect!"); @@ -1951,8 +1940,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, nsLayoutUtils::SCROLLABLE_SAME_DOC | nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN)); - nsDisplayListBuilder::AutoBuildingDisplayList - buildingDisplayList(aBuilder, this, dirtyRect, true); DisplayListClipState::AutoSaveRestore clipState(aBuilder); if (isTransformed || useOpacity || useBlendMode || usingSVGEffects || useStickyPosition) { @@ -1965,7 +1952,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, } nsDisplayListCollection set; - { + { + nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, true); DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); nsDisplayListBuilder::AutoInTransformSetter inTransformSetter(aBuilder, inTransform); @@ -2006,7 +1994,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, set.PositionedDescendants()->DeleteAll(); set.Outlines()->DeleteAll(); } - + // This z-order sort also sorts secondarily by content order. We need to do // this so that boxes produced by the same element are placed together // in the sort. Consider a position:relative inline element that breaks @@ -2014,7 +2002,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, // children should be z-ordered after all the boxes for the position:relative // element itself. set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent()); - + nsDisplayList resultList; // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html // 1,2: backgrounds and borders @@ -2084,8 +2072,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList)); } - /* If we're going to apply a transformation and don't have preserve-3d set, wrap - * everything in an nsDisplayTransform. If there's nothing in the list, don't add + /* If we're going to apply a transformation and don't have preserve-3d set, wrap + * everything in an nsDisplayTransform. If there's nothing in the list, don't add * anything. * * For the preserve-3d case we want to individually wrap every child in the list with @@ -2098,15 +2086,12 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, if (isTransformed && !resultList.IsEmpty()) { // Restore clip state now so nsDisplayTransform is clipped properly. clipState.Restore(); - // Revert to the dirtyrect coming in from the parent, without our transform - // taken into account. - buildingDisplayList.SetDirtyRect(aDirtyRect + offsetToReferenceFrame); if (Preserves3DChildren()) { WrapPreserve3DList(this, aBuilder, &resultList); } else { resultList.AppendNewToTop( - new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList, dirtyRect)); + new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList)); } } @@ -2300,8 +2285,15 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, NS_ASSERTION(!isStackingContext || pseudoStackingContext, "Stacking contexts must also be pseudo-stacking-contexts"); + bool isInFixedPos = aBuilder->IsInFixedPos() || + (isPositioned && + disp->mPosition == NS_STYLE_POSITION_FIXED && + nsLayoutUtils::IsReallyFixedPos(child)); + nsDisplayListBuilder::AutoInFixedPosSetter + buildingInFixedPos(aBuilder, isInFixedPos); + nsDisplayListBuilder::AutoBuildingDisplayList - buildingForChild(aBuilder, child, dirty, pseudoStackingContext); + buildingForChild(aBuilder, child, pseudoStackingContext); DisplayListClipState::AutoClipMultiple clipState(aBuilder); CheckForTouchEventHandler(aBuilder, child); @@ -5235,12 +5227,6 @@ nsIFrame::GetScrollableOverflowRectRelativeToParent() const return GetScrollableOverflowRect() + mRect.TopLeft(); } -nsRect -nsIFrame::GetVisualOverflowRectRelativeToParent() const -{ - return GetVisualOverflowRect() + mRect.TopLeft(); -} - nsRect nsIFrame::GetScrollableOverflowRectRelativeToSelf() const { diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index c7b957720e0..4b6137eaaa5 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -271,6 +271,7 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, transform.Scale(r.Width()/canvasSize.width, r.Height()/canvasSize.height); layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this)); + layer->SetVisibleRegion(nsIntRect(0, 0, canvasSize.width, canvasSize.height)); return layer.forget(); } diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 56478119839..76d48a857d4 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -2269,15 +2269,6 @@ public: */ nsRect GetVisualOverflowRectRelativeToSelf() const; - /** - * Same as GetVisualOverflowRect, except relative to the parent - * frame. - * - * @return the rect relative to the parent frame, in the parent frame's - * coordinate system - */ - nsRect GetVisualOverflowRectRelativeToParent() const; - /** * Returns this frame's visual overflow rect as it would be before taking * account of SVG effects or transforms. The rect returned is relative to diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index b66a9fa3528..d285a76b933 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1425,6 +1425,7 @@ nsDisplayImage::ConfigureLayer(ImageLayer *aLayer, const nsIntPoint& aOffset) transform.Scale(destRect.Width()/imageWidth, destRect.Height()/imageHeight); aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); + aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight)); } void diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index c5ef72c2e7b..665052143ca 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -839,12 +839,6 @@ nsObjectFrame::PaintPrintPlugin(nsIFrame* aFrame, nsRenderingContext* aCtx, static_cast(aFrame)->PrintPlugin(*aCtx, aDirtyRect); } -/** - * nsDisplayPluginReadback creates an active ReadbackLayer. The ReadbackLayer - * obtains from the compositor the contents of the window underneath - * the ReadbackLayer, which we then use as an opaque buffer for plugins to - * asynchronously draw onto. - */ class nsDisplayPluginReadback : public nsDisplayItem { public: nsDisplayPluginReadback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) @@ -860,6 +854,9 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("PluginReadback", TYPE_PLUGIN_READBACK) @@ -892,6 +889,25 @@ nsDisplayPluginReadback::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) return GetDisplayItemBounds(aBuilder, this, mFrame); } +bool +nsDisplayPluginReadback::ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) +{ + if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion)) + return false; + + nsRect expand; + bool snap; + expand.IntersectRect(aAllowVisibleRegionExpansion, GetBounds(aBuilder, &snap)); + // *Add* our bounds to the visible region so that stuff underneath us is + // likely to be made visible, so we can use it for a background! This is + // a bit crazy since we normally only subtract from the visible region. + aVisibleRegion->Or(*aVisibleRegion, expand); + return true; +} + #ifdef MOZ_WIDGET_ANDROID class nsDisplayPluginVideo : public nsDisplayItem { @@ -909,6 +925,9 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; + virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("PluginVideo", TYPE_PLUGIN_VIDEO) @@ -939,6 +958,15 @@ nsDisplayPluginVideo::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) return GetDisplayItemBounds(aBuilder, this, mFrame); } +bool +nsDisplayPluginVideo::ComputeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) +{ + return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion); +} + #endif nsRect @@ -959,7 +987,8 @@ nsDisplayPlugin::Paint(nsDisplayListBuilder* aBuilder, bool nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) { if (aBuilder->IsForPluginGeometry()) { nsObjectFrame* f = static_cast(mFrame); @@ -998,7 +1027,8 @@ nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder, } } - return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion); + return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion); } nsRegion @@ -1582,6 +1612,7 @@ nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder, transform.Translate(p.x, p.y); layer->SetBaseTransform(Matrix4x4::From2D(transform)); + layer->SetVisibleRegion(ThebesIntRect(IntRect(IntPoint(0, 0), size))); return layer.forget(); } diff --git a/layout/generic/nsObjectFrame.h b/layout/generic/nsObjectFrame.h index ce7d056745b..8e7b3d27dce 100644 --- a/layout/generic/nsObjectFrame.h +++ b/layout/generic/nsObjectFrame.h @@ -319,7 +319,8 @@ public: virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) MOZ_OVERRIDE; + nsRegion* aVisibleRegion, + const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("Plugin", TYPE_PLUGIN) diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp index 29efdea7c32..acbd32d8b68 100644 --- a/layout/generic/nsPageFrame.cpp +++ b/layout/generic/nsPageFrame.cpp @@ -414,22 +414,22 @@ PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, aList->AppendToTop(&newList); } -static void +static nsresult BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, nsPageFrame* aPage, nsIFrame* aExtraPage, - const nsRect& aDirtyRect, nsDisplayList* aList) + nsDisplayList* aList) { - // The only content in aExtraPage we care about is out-of-flow content whose - // placeholders have occurred in aPage. If - // NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO is not set, then aExtraPage has - // no such content. - if (!aExtraPage->HasAnyStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) { - return; - } nsDisplayList list; - aExtraPage->BuildDisplayListForStackingContext(aBuilder, aDirtyRect, &list); + // Pass an empty dirty rect since we're only interested in finding + // placeholders whose out-of-flows are in the page + // aBuilder->GetReferenceFrame(), and the paths to those placeholders + // have already been marked as NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO. + // Note that we should still do a prune step since we don't want to + // rely on dirty-rect checking for correctness. + aExtraPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list); PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, &list); aList->AppendToTop(&list); + return NS_OK; } static nsIFrame* @@ -506,8 +506,8 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, clipState.Clear(); clipState.ClipContainingBlockDescendants(clipRect, nullptr); - nsRect dirtyRect = child->GetVisualOverflowRectRelativeToSelf(); - child->BuildDisplayListForStackingContext(aBuilder, dirtyRect, &content); + child->BuildDisplayListForStackingContext(aBuilder, + child->GetVisualOverflowRectRelativeToSelf(), &content); // We may need to paint out-of-flow frames whose placeholders are // on other pages. Add those pages to our display list. Note that @@ -518,16 +518,9 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // following placeholders to their out-of-flows) end up on the list. nsIFrame* page = child; while ((page = GetNextPage(page)) != nullptr) { - BuildDisplayListForExtraPage(aBuilder, this, page, - dirtyRect + child->GetOffsetTo(page), &content); + BuildDisplayListForExtraPage(aBuilder, this, page, &content); } - // Invoke AutoBuildingDisplayList to ensure that the correct dirtyRect - // is used to compute the visible rect if AddCanvasBackgroundColorItem - // creates a display item. - nsDisplayListBuilder::AutoBuildingDisplayList - building(aBuilder, child, dirtyRect, true); - // Add the canvas background color to the bottom of the list. This // happens after we've built the list so that AddCanvasBackgroundColorItem // can monkey with the contents if necessary. @@ -537,8 +530,7 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, *aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0)); } - content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child, - &content, content.GetVisibleRect(), ::ComputePageTransform)); + content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child, &content, ::ComputePageTransform)); set.Content()->AppendToTop(&content); diff --git a/layout/generic/nsSimplePageSequenceFrame.cpp b/layout/generic/nsSimplePageSequenceFrame.cpp index fb72684ea91..824725d8c5e 100644 --- a/layout/generic/nsSimplePageSequenceFrame.cpp +++ b/layout/generic/nsSimplePageSequenceFrame.cpp @@ -788,22 +788,16 @@ nsSimplePageSequenceFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, clipState.Clear(); nsIFrame* child = GetFirstPrincipalChild(); - nsRect dirty = aDirtyRect; - dirty.ScaleInverseRoundOut(PresContext()->GetPrintPreviewScale()); - while (child) { - if (child->GetVisualOverflowRectRelativeToParent().Intersects(dirty)) { - child->BuildDisplayListForStackingContext(aBuilder, - dirty - child->GetPosition(), &content); - aBuilder->ResetMarkedFramesForDisplayList(); - } + child->BuildDisplayListForStackingContext(aBuilder, + child->GetVisualOverflowRectRelativeToSelf(), &content); + aBuilder->ResetMarkedFramesForDisplayList(); child = child->GetNextSibling(); } } content.AppendNewToTop(new (aBuilder) - nsDisplayTransform(aBuilder, this, &content, content.GetVisibleRect(), - ::ComputePageSequenceTransform)); + nsDisplayTransform(aBuilder, this, &content, ::ComputePageSequenceTransform)); aLists.Content()->AppendToTop(&content); } diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 30c4893bb0d..fa40ed672d8 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -444,6 +444,13 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, haveDisplayPort || presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive()); + // Don't let in fixed pos propagate down to child documents. This makes + // it a little less effective but doesn't regress an important case of a + // child document being in a fixed pos element where we would do no occlusion + // at all if we let it propagate down. + nsDisplayListBuilder::AutoInFixedPosSetter + buildingInFixedPos(aBuilder, false); + nsDisplayList childItems; { diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index a3cf2a1015a..ce5377baccf 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -219,6 +219,7 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder, transform.Translate(p.x, p.y); transform.Scale(r.Width()/frameSize.width, r.Height()/frameSize.height); layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform)); + layer->SetVisibleRegion(nsIntRect(0, 0, frameSize.width, frameSize.height)); nsRefPtr result = layer.forget(); return result.forget(); } diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index aad641feac4..10211ab9430 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -873,6 +873,7 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, } static_cast(layer.get())->SetReferentId(id); nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder); + layer->SetVisibleRegion(aVisibleRect - offset); // We can only have an offset if we're a child of an inactive // container, but our display item is LAYER_ACTIVE_FORCE which // forces all layers above to be active. @@ -925,6 +926,7 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, mBackgroundColor, aManager, aFrame); } + mContainer->SetVisibleRegion(aVisibleRect); return nsRefPtr(mContainer).forget(); } diff --git a/layout/reftests/bugs/1022612-1-ref.html b/layout/reftests/bugs/1022612-1-ref.html deleted file mode 100644 index ffe8398e037..00000000000 --- a/layout/reftests/bugs/1022612-1-ref.html +++ /dev/null @@ -1,7 +0,0 @@ - -
- - - - -
diff --git a/layout/reftests/bugs/1022612-1.html b/layout/reftests/bugs/1022612-1.html deleted file mode 100644 index 1d329712175..00000000000 --- a/layout/reftests/bugs/1022612-1.html +++ /dev/null @@ -1,7 +0,0 @@ - -
- - - - -
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 64f2b120d16..d9c9f8bd3c3 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1790,7 +1790,7 @@ fuzzy-if(OSX==10.6,2,30) skip-if(B2G&&browserIsRemote) == 933264-1.html 933264-1 == 936670-1.svg 936670-1-ref.svg == 941940-1.html 941940-1-ref.html fails == 942017.html 942017-ref.html # bug 942017 -fuzzy-if(B2G,1,7) == 942672-1.html 942672-1-ref.html +== 942672-1.html 942672-1-ref.html == 953334-win32-clipping.html 953334-win32-clipping-ref.html == 956513-1.svg 956513-1-ref.svg == 944291-1.html 944291-1-ref.html @@ -1813,5 +1813,4 @@ pref(layout.css.overflow-clip-box.enabled,true) == 992447.html 992447-ref.html pref(layout.css.sticky.enabled,true) == 1005405-1.html 1005405-1-ref.html pref(layout.css.will-change.enabled,true) == 1018522-1.html 1018522-1-ref.html pref(browser.display.use_document_fonts,0) == 1022481-1.html 1022481-1-ref.html -== 1022612-1.html 1022612-1-ref.html == 1024473-1.html 1024473-1-ref.html diff --git a/layout/reftests/forms/fieldset/positioned-container-1-ref.html b/layout/reftests/forms/fieldset/positioned-container-1-ref.html index b7988f37914..2b161f9f3ff 100644 --- a/layout/reftests/forms/fieldset/positioned-container-1-ref.html +++ b/layout/reftests/forms/fieldset/positioned-container-1-ref.html @@ -4,7 +4,7 @@
Legend
-
Abs-pos
+
Abs-pos
diff --git a/layout/reftests/forms/fieldset/positioned-container-1.html b/layout/reftests/forms/fieldset/positioned-container-1.html index 04e81ca6b57..51398591263 100644 --- a/layout/reftests/forms/fieldset/positioned-container-1.html +++ b/layout/reftests/forms/fieldset/positioned-container-1.html @@ -4,7 +4,7 @@
Legend
-
Abs-pos
+
Abs-pos