diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index f629ba414605..7ebd53658c38 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -269,14 +269,9 @@ public: /** * This is the method that actually walks a display list and builds - * the child layers. We invoke it recursively to process clipped sublists. - * @param aClipRect the clip rect to apply to the list items, or null - * if no clipping is required + * the child layers. */ - void ProcessDisplayItems(const nsDisplayList& aList, - DisplayItemClip& aClip, - uint32_t aFlags, - const nsIFrame* aForceActiveScrolledRoot = nullptr); + 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 @@ -1403,9 +1398,7 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, #ifdef MOZ_DUMP_PAINTING /** - * Returns the appunits per dev pixel for the item's frame. The item must - * have a frame because only nsDisplayClip items don't have a frame, - * and those items are flattened away by ProcessDisplayItems. + * Returns the appunits per dev pixel for the item's frame */ static int32_t AppUnitsPerDevPixel(nsDisplayItem* aItem) @@ -1810,7 +1803,7 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState, nsRegion opaqueClipped; nsRegionRectIterator iter(opaque); for (const nsRect* r = iter.Next(); r; r = iter.Next()) { - opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersect(*r)); + opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersectInward(*r)); } nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap); @@ -1996,16 +1989,6 @@ ContainerState::ChooseActiveScrolledRoot(const nsDisplayList& aList, const nsIFrame **aActiveScrolledRoot) { for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { - nsDisplayItem::Type type = item->GetType(); - if (type == nsDisplayItem::TYPE_CLIP || - type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) { - if (ChooseActiveScrolledRoot(*item->GetSameCoordinateSystemChildren(), - aActiveScrolledRoot)) { - return true; - } - continue; - } - LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters); // Don't use an item that won't be part of any ThebesLayers to pick the // active scrolled root. @@ -2039,9 +2022,7 @@ ContainerState::ChooseActiveScrolledRoot(const nsDisplayList& aList, */ void ContainerState::ProcessDisplayItems(const nsDisplayList& aList, - DisplayItemClip& aClip, - uint32_t aFlags, - const nsIFrame* aForceActiveScrolledRoot) + uint32_t aFlags) { PROFILER_LABEL("ContainerState", "ProcessDisplayItems"); @@ -2052,9 +2033,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // layer, so we need to choose which active scrolled root to use for all // items. if (aFlags & NO_COMPONENT_ALPHA) { - if (aForceActiveScrolledRoot) { - lastActiveScrolledRoot = aForceActiveScrolledRoot; - } else if (!ChooseActiveScrolledRoot(aList, &lastActiveScrolledRoot)) { + if (!ChooseActiveScrolledRoot(aList, &lastActiveScrolledRoot)) { lastActiveScrolledRoot = mContainerReferenceFrame; } @@ -2062,14 +2041,6 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, } for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { - nsDisplayItem::Type type = item->GetType(); - if (type == nsDisplayItem::TYPE_CLIP || - type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) { - DisplayItemClip childClip(aClip, item); - ProcessDisplayItems(*item->GetSameCoordinateSystemChildren(), childClip, aFlags, lastActiveScrolledRoot); - continue; - } - NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item), "items in a container layer should all have the same app units per dev pixel"); @@ -2079,9 +2050,10 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, nsRect itemContent = item->GetBounds(mBuilder, &snap); nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap); nsIntRect clipRect; - if (aClip.HasClip()) { - itemContent.IntersectRect(itemContent, aClip.GetClipRect()); - clipRect = ScaleToNearestPixels(aClip.NonRoundedIntersection()); + const DisplayItemClip& itemClip = item->GetClip(); + if (itemClip.HasClip()) { + itemContent.IntersectRect(itemContent, itemClip.GetClipRect()); + clipRect = ScaleToNearestPixels(itemClip.GetClipRect()); itemDrawRect.IntersectRect(itemDrawRect, clipRect); clipRect.MoveBy(mParameters.mOffset); } @@ -2127,7 +2099,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // InvalidateForLayerChange doesn't need the new layer pointer. // We also need to check the old data now, because BuildLayer // can overwrite it. - InvalidateForLayerChange(item, nullptr, aClip, topLeft, nullptr); + InvalidateForLayerChange(item, nullptr, itemClip, topLeft, nullptr); // If the item would have its own layer but is invisible, just hide it. // Note that items without their own layers can't be skipped this @@ -2138,11 +2110,13 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, continue; } + + nsDisplayItem::Type type = item->GetType(); bool setVisibleRegion = type != nsDisplayItem::TYPE_TRANSFORM; if (setVisibleRegion) { mParameters.mAncestorClipRect = nullptr; } else { - mParameters.mAncestorClipRect = aClip.mHaveClipRect ? &clipRect : nullptr; + mParameters.mAncestorClipRect = itemClip.HasClip() ? &clipRect : nullptr; } // Just use its layer. @@ -2170,17 +2144,18 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // overwritten by CompositorParent when doing scroll compensation on // fixed layers. This means we need to make sure transform layers are not // marked as fixed. - ownLayer->SetIsFixedPosition(isFixed && type != nsDisplayItem::TYPE_TRANSFORM); + ownLayer->SetIsFixedPosition( + isFixed && item->GetType() != nsDisplayItem::TYPE_TRANSFORM); // Update that layer's clip and visible rects. NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager"); NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData), "We shouldn't have a FrameLayerBuilder-managed layer here!"); - NS_ASSERTION(aClip.HasClip() || - aClip.GetRoundedRectCount() == 0, + NS_ASSERTION(itemClip.HasClip() || + itemClip.GetRoundedRectCount() == 0, "If we have rounded rects, we must have a clip rect"); // It has its own layer. Update that layer's clip and visible rects. - if (aClip.HasClip()) { + if (itemClip.HasClip()) { ownLayer->SetClipRect(&clipRect); } else { ownLayer->SetClipRect(nullptr); @@ -2203,8 +2178,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // rounded rectangle clipping using mask layers // (must be done after visible rect is set on layer) - if (aClip.IsRectClippedByRoundedCorner(itemContent)) { - SetupMaskLayer(ownLayer, aClip); + if (itemClip.IsRectClippedByRoundedCorner(itemContent)) { + SetupMaskLayer(ownLayer, itemClip); } ContainerLayer* oldContainer = ownLayer->GetParent(); @@ -2222,28 +2197,28 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, */ nsAutoPtr dummy; mLayerBuilder->AddLayerDisplayItem(ownLayer, item, - aClip, layerState, + itemClip, layerState, topLeft, nullptr, dummy); } else { ThebesLayerData* data = - FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip, + FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, itemClip, activeScrolledRoot, topLeft); data->mLayer->SetIsFixedPosition(isFixed); nsAutoPtr geometry(item->AllocateGeometry(mBuilder)); - InvalidateForLayerChange(item, data->mLayer, aClip, topLeft, geometry); + InvalidateForLayerChange(item, data->mLayer, itemClip, topLeft, geometry); - mLayerBuilder->AddThebesDisplayItem(data->mLayer, item, aClip, + mLayerBuilder->AddThebesDisplayItem(data->mLayer, item, itemClip, mContainerFrame, layerState, topLeft, geometry); // check to see if the new item has rounded rect clips in common with // other items in the layer - data->UpdateCommonClipCount(aClip); + data->UpdateCommonClipCount(itemClip); } } } @@ -2464,7 +2439,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer, } } ClippedDisplayItem* cdi = - entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip, + entry->mItems.AppendElement(ClippedDisplayItem(aItem, mContainerLayerGeneration)); cdi->mInactiveLayerManager = tempManager; } @@ -2919,8 +2894,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, aContainerFrame, aContainerItem, containerLayer, scaleParameters); - DisplayItemClip clip; - state.ProcessDisplayItems(aChildren, clip, stateFlags); + state.ProcessDisplayItems(aChildren, stateFlags); // Set CONTENT_COMPONENT_ALPHA if any of our children have it. // This is suboptimal ... a child could have text that's over transparent @@ -3236,15 +3210,16 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, for (i = items.Length(); i > 0; --i) { ClippedDisplayItem* cdi = &items[i - 1]; + const DisplayItemClip& clip = cdi->mItem->GetClip(); NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == appUnitsPerDevPixel, "a thebes layer should contain items only at the same zoom"); - NS_ABORT_IF_FALSE(cdi->mClip.HasClip() || - cdi->mClip.GetRoundedRectCount() == 0, + NS_ABORT_IF_FALSE(clip.HasClip() || + clip.GetRoundedRectCount() == 0, "If we have rounded rects, we must have a clip rect"); - if (!cdi->mClip.IsRectAffectedByClip(visible.GetBounds())) { + if (!clip.IsRectAffectedByClip(visible.GetBounds())) { cdi->mItem->RecomputeVisibility(builder, &visible); continue; } @@ -3252,12 +3227,12 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, // Do a little dance to account for the fact that we're clipping // to cdi->mClipRect nsRegion clipped; - clipped.And(visible, cdi->mClip.NonRoundedIntersection()); + clipped.And(visible, clip.NonRoundedIntersection()); nsRegion finalClipped = clipped; cdi->mItem->RecomputeVisibility(builder, &finalClipped); // If we have rounded clip rects, don't subtract from the visible // region since we aren't displaying everything inside the rect. - if (cdi->mClip.GetRoundedRectCount() == 0) { + if (clip.GetRoundedRectCount() == 0) { nsRegion removed; removed.Sub(clipped, finalClipped); nsRegion newVisible; @@ -3267,9 +3242,6 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, visible = newVisible; } } - if (!cdi->mClip.IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) { - cdi->mClip.RemoveRoundedCorners(); - } } nsRefPtr rc = new nsRenderingContext(); @@ -3277,6 +3249,7 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, DisplayItemClip currentClip; bool currentClipIsSetInContext = false; + DisplayItemClip tmpClip; for (i = 0; i < items.Length(); ++i) { ClippedDisplayItem* cdi = &items[i]; @@ -3286,14 +3259,21 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, // If the new desired clip state is different from the current state, // update the clip. - if (currentClipIsSetInContext != cdi->mClip.HasClip() || - (cdi->mClip.HasClip() && cdi->mClip != currentClip)) { + const DisplayItemClip* clip = &cdi->mItem->GetClip(); + if (clip->GetRoundedRectCount() > 0 && + !clip->IsRectClippedByRoundedCorner(cdi->mItem->GetVisibleRect())) { + tmpClip = *clip; + tmpClip.RemoveRoundedCorners(); + clip = &tmpClip; + } + if (currentClipIsSetInContext != clip->HasClip() || + (clip->HasClip() && *clip != currentClip)) { if (currentClipIsSetInContext) { aContext->Restore(); } - currentClipIsSetInContext = cdi->mClip.HasClip(); + currentClipIsSetInContext = clip->HasClip(); if (currentClipIsSetInContext) { - currentClip = cdi->mClip; + currentClip = *clip; aContext->Save(); NS_ASSERTION(commonClipCount < 100, "Maybe you really do have more than a hundred clipping rounded rects, or maybe something has gone wrong."); diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index 2cbe0002d0cc..f841f0ea4307 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -500,11 +500,10 @@ protected: * These are only stored during the paint process, so that the * DrawThebesLayer callback can figure out which items to draw for the * ThebesLayer. - * mItem always has an underlying frame. */ struct ClippedDisplayItem { - ClippedDisplayItem(nsDisplayItem* aItem, const DisplayItemClip& aClip, uint32_t aGeneration) - : mItem(aItem), mClip(aClip), mContainerLayerGeneration(aGeneration) + ClippedDisplayItem(nsDisplayItem* aItem, uint32_t aGeneration) + : mItem(aItem), mContainerLayerGeneration(aGeneration) { } @@ -519,7 +518,6 @@ protected: */ nsRefPtr mInactiveLayerManager; - DisplayItemClip mClip; uint32_t mContainerLayerGeneration; }; diff --git a/layout/base/nsDisplayItemTypesList.h b/layout/base/nsDisplayItemTypesList.h index d54d57a471c1..f32d5b9169de 100644 --- a/layout/base/nsDisplayItemTypesList.h +++ b/layout/base/nsDisplayItemTypesList.h @@ -15,8 +15,6 @@ DECLARE_DISPLAY_ITEM_TYPE(CANVAS_FOCUS) DECLARE_DISPLAY_ITEM_TYPE(CARET) DECLARE_DISPLAY_ITEM_TYPE(CHECKED_CHECKBOX) DECLARE_DISPLAY_ITEM_TYPE(CHECKED_RADIOBUTTON) -DECLARE_DISPLAY_ITEM_TYPE(CLIP) -DECLARE_DISPLAY_ITEM_TYPE(CLIP_ROUNDED_RECT) DECLARE_DISPLAY_ITEM_TYPE(COLUMN_RULE) DECLARE_DISPLAY_ITEM_TYPE(COMBOBOX_FOCUS) DECLARE_DISPLAY_ITEM_TYPE(EVENT_RECEIVER) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index e2711d0a2c2d..dccff522e58e 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -895,8 +895,7 @@ nsRect nsDisplayList::GetBounds(nsDisplayListBuilder* aBuilder) const { nsRect bounds; for (nsDisplayItem* i = GetBottom(); i != nullptr; i = i->GetAbove()) { - bool snap; - bounds.UnionRect(bounds, i->GetBounds(aBuilder, &snap)); + bounds.UnionRect(bounds, i->GetClippedBounds(aBuilder)); } return bounds; } @@ -907,7 +906,8 @@ nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder, PROFILER_LABEL("nsDisplayList", "ComputeVisibilityForRoot"); nsRegion r; r.And(*aVisibleRegion, GetBounds(aBuilder)); - return ComputeVisibilityForSublist(aBuilder, nullptr, aVisibleRegion, r.GetBounds(), r.GetBounds()); + return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, + r.GetBounds(), r.GetBounds()); } static nsRegion @@ -931,7 +931,15 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) opaque = aItem->GetBounds(aBuilder, &snap); } } - return opaque; + if (opaque.IsEmpty()) { + return opaque; + } + nsRegion opaqueClipped; + nsRegionRectIterator iter(opaque); + for (const nsRect* r = iter.Next(); r; r = iter.Next()) { + opaqueClipped.Or(opaqueClipped, aItem->GetClip().ApproximateIntersectInward(*r)); + } + return opaqueClipped; } static nsRect @@ -958,17 +966,16 @@ GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) bool nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aForItem, nsRegion* aVisibleRegion, const nsRect& aListVisibleBounds, const nsRect& aAllowVisibleRegionExpansion) { - bool snap; #ifdef DEBUG nsRegion r; r.And(*aVisibleRegion, GetBounds(aBuilder)); NS_ASSERTION(r.GetBounds().IsEqualInterior(aListVisibleBounds), "bad aListVisibleBounds"); #endif + mVisibleRect = aListVisibleBounds; bool anyVisible = false; @@ -981,13 +988,6 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, nsDisplayItem* item = elements[i]; nsDisplayItem* belowItem = i < 1 ? nullptr : elements[i - 1]; - NS_ASSERTION(!aForItem || - item->GetType() != nsDisplayItem::TYPE_TRANSFORM || - item->GetUnderlyingFrame() != aForItem->GetUnderlyingFrame() || - aForItem->ReferenceFrame() != aForItem->GetUnderlyingFrame(), - "If we have an nsDisplayTransform child (for the same frame)," - "then we shouldn't be our own reference frame!"); - nsDisplayList* list = item->GetSameCoordinateSystemChildren(); if (aBuilder->AllowMergingAndFlattening()) { if (belowItem && item->TryMerge(aBuilder, belowItem)) { @@ -1006,7 +1006,7 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, } } - nsRect bounds = item->GetBounds(aBuilder, &snap); + nsRect bounds = item->GetClippedBounds(aBuilder); nsRegion itemVisible; if (ForceVisiblityForFixedItem(aBuilder, item)) { @@ -1016,7 +1016,8 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, } item->mVisibleRect = itemVisible.GetBounds(); - if (item->ComputeVisibility(aBuilder, aVisibleRegion, aAllowVisibleRegionExpansion)) { + if (item->ComputeVisibility(aBuilder, aVisibleRegion, + aAllowVisibleRegionExpansion.Intersect(bounds))) { anyVisible = true; nsRegion opaque = TreatAsOpaque(item, aBuilder); // Subtract opaque item from the visible region @@ -1313,7 +1314,8 @@ void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, aState->mItemBuffer.SetLength(i); bool snap; - if (aRect.Intersects(item->GetBounds(aBuilder, &snap))) { + nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect); + if (item->GetClip().MayIntersect(r)) { nsAutoTArray outFrames; item->HitTest(aBuilder, aRect, aState, &outFrames); @@ -1413,39 +1415,6 @@ static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2, return index1 <= index2; } -void nsDisplayList::ExplodeAnonymousChildLists(nsDisplayListBuilder* aBuilder) { - // See if there's anything to do - bool anyAnonymousItems = false; - nsDisplayItem* i; - for (i = GetBottom(); i != nullptr; i = i->GetAbove()) { - if (!i->GetUnderlyingFrame()) { - anyAnonymousItems = true; - break; - } - } - if (!anyAnonymousItems) - return; - - nsDisplayList tmp; - while ((i = RemoveBottom()) != nullptr) { - if (i->GetUnderlyingFrame()) { - tmp.AppendToTop(i); - } else { - nsDisplayList* list = i->GetSameCoordinateSystemChildren(); - NS_ASSERTION(list, "leaf items can't be anonymous"); - list->ExplodeAnonymousChildLists(aBuilder); - nsDisplayItem* j; - while ((j = list->RemoveBottom()) != nullptr) { - tmp.AppendToTop(static_cast(i)-> - WrapWithClone(aBuilder, j)); - } - i->~nsDisplayItem(); - } - } - - AppendToTop(&tmp); -} - void nsDisplayList::SortByZOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor) { Sort(aBuilder, IsZOrderLEQ, aCommonAncestor); @@ -1458,7 +1427,6 @@ void nsDisplayList::SortByContentOrder(nsDisplayListBuilder* aBuilder, void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder, SortLEQ aCmp, void* aClosure) { - ExplodeAnonymousChildLists(aBuilder); ::Sort(this, Count(), aCmp, aClosure); } @@ -1479,8 +1447,7 @@ nsDisplayItem::ForceActiveLayers() bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion) { - bool snap; - nsRect bounds = GetBounds(aBuilder, &snap); + nsRect bounds = GetClippedBounds(aBuilder); nsRegion itemVisible; if (ForceVisiblityForFixedItem(aBuilder, this)) { @@ -1501,6 +1468,14 @@ nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, return true; } +nsRect +nsDisplayItem::GetClippedBounds(nsDisplayListBuilder* aBuilder) +{ + bool snap; + nsRect r = GetBounds(aBuilder, &snap); + return GetClip().ApplyNonRoundedIntersection(r); +} + nsRect nsDisplaySolidColor::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { @@ -2582,9 +2557,25 @@ bool nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion, const nsRect& aAllowVisibleRegionExpansion) { - return mList.ComputeVisibilityForSublist(aBuilder, this, aVisibleRegion, - mVisibleRect, - aAllowVisibleRegionExpansion); + // Convert the passed in visible region to our appunits. + nsRegion visibleRegion; + // mVisibleRect has been clipped to GetClippedBounds + visibleRegion.And(*aVisibleRegion, mVisibleRect); + nsRegion originalVisibleRegion = visibleRegion; + + bool retval = + mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, + mVisibleRect, + aAllowVisibleRegionExpansion); + + nsRegion removed; + // removed = originalVisibleRegion - visibleRegion + removed.Sub(originalVisibleRegion, visibleRegion); + // aVisibleRegion = aVisibleRegion - removed (modulo any simplifications + // SubtractFromVisibleRegion does) + aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed); + + return retval; } nsRegion @@ -2811,8 +2802,7 @@ nsDisplayOpacity::ComputeVisibility(nsDisplayListBuilder* aBuilder, // our children in the temporary compositing buffer, because if our children // paint our entire bounds opaquely then we don't need an alpha channel in // the temporary compositing buffer. - bool snap; - nsRect bounds = GetBounds(aBuilder, &snap); + nsRect bounds = GetClippedBounds(aBuilder); nsRegion visibleUnderChildren; visibleUnderChildren.And(*aVisibleRegion, bounds); nsRect allowExpansion = bounds.Intersect(aAllowVisibleRegionExpansion); @@ -2829,6 +2819,8 @@ bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* a // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplayOpacity if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent()) return false; + if (aItem->GetClip() != GetClip()) + return false; MergeFromTrackingMergedFrames(static_cast(aItem)); return true; } @@ -2948,6 +2940,8 @@ bool nsDisplayFixedPosition::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayI nsDisplayFixedPosition* other = static_cast(aItem); if (other->mFixedPosFrame != mFixedPosFrame) return false; + if (aItem->GetClip() != GetClip()) + return false; MergeFromTrackingMergedFrames(other); return true; } @@ -3059,11 +3053,13 @@ nsDisplayScrollLayer::ComputeVisibility(nsDisplayListBuilder* aBuilder, childVisibleRegion.GetBounds().Intersect(mList.GetBounds(aBuilder)); nsRect allowExpansion = boundedRect.Intersect(aAllowVisibleRegionExpansion); bool visible = mList.ComputeVisibilityForSublist( - aBuilder, this, &childVisibleRegion, boundedRect, allowExpansion); + aBuilder, &childVisibleRegion, boundedRect, allowExpansion); + // We don't allow this computation to influence aVisibleRegion, on the + // assumption that the layer can be asynchronously scrolled so we'll + // definitely need all the content under it. mVisibleRect = boundedRect; return visible; - } else { return nsDisplayWrapList::ComputeVisibility(aBuilder, aVisibleRegion, aAllowVisibleRegionExpansion); @@ -3087,11 +3083,13 @@ nsDisplayScrollLayer::TryMerge(nsDisplayListBuilder* aBuilder, if (aItem->GetType() != TYPE_SCROLL_LAYER) { return false; } - nsDisplayScrollLayer* other = static_cast(aItem); if (other->mScrolledFrame != this->mScrolledFrame) { return false; } + if (aItem->GetClip() != GetClip()) { + return false; + } NS_ASSERTION(other->mReferenceFrame == mReferenceFrame, "Must have the same reference frame!"); @@ -3190,165 +3188,6 @@ nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) return RemoveScrollLayerCount() == 1; } -nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder, - nsIFrame* aFrame, nsDisplayItem* aItem, - const nsRect& aRect) - : nsDisplayWrapList(aBuilder, aFrame, aItem, - aFrame == aItem->GetUnderlyingFrame() ? aItem->ReferenceFrame() : aBuilder->FindReferenceFrameFor(aFrame), - aFrame == aItem->GetUnderlyingFrame() ? aItem->ToReferenceFrame() : aBuilder->ToReferenceFrame(aFrame)), - mClip(aRect) { - MOZ_COUNT_CTOR(nsDisplayClip); -} - -nsDisplayClip::nsDisplayClip(nsDisplayListBuilder* aBuilder, - nsIFrame* aFrame, nsDisplayList* aList, - const nsRect& aRect) - : nsDisplayWrapList(aBuilder, aFrame, aList), mClip(aRect) { - MOZ_COUNT_CTOR(nsDisplayClip); -} - -nsRect nsDisplayClip::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { - nsRect r = nsDisplayWrapList::GetBounds(aBuilder, aSnap); - *aSnap = false; - return mClip.Intersect(r); -} - -#ifdef NS_BUILD_REFCNT_LOGGING -nsDisplayClip::~nsDisplayClip() { - MOZ_COUNT_DTOR(nsDisplayClip); -} -#endif - -void nsDisplayClip::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) { - NS_ERROR("nsDisplayClip should have been flattened away for painting"); -} - -bool nsDisplayClip::ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion, - const nsRect& aAllowVisibleRegionExpansion) { - nsRegion clipped; - clipped.And(*aVisibleRegion, mClip); - - nsRegion finalClipped(clipped); - nsRect allowExpansion = mClip.Intersect(aAllowVisibleRegionExpansion); - bool anyVisible = - nsDisplayWrapList::ComputeVisibility(aBuilder, &finalClipped, - allowExpansion); - - nsRegion removed; - removed.Sub(clipped, finalClipped); - aBuilder->SubtractFromVisibleRegion(aVisibleRegion, removed); - - return anyVisible; -} - -bool nsDisplayClip::TryMerge(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem) { - if (aItem->GetType() != TYPE_CLIP) - return false; - nsDisplayClip* other = static_cast(aItem); - if (!other->mClip.IsEqualInterior(mClip)) - return false; - // No need to track merged frames for clipping - MergeFrom(other); - return true; -} - -nsDisplayWrapList* nsDisplayClip::WrapWithClone(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem) { - return new (aBuilder) - nsDisplayClip(aBuilder, aItem->GetUnderlyingFrame(), aItem, mClip); -} - -nsDisplayClipRoundedRect::nsDisplayClipRoundedRect( - nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayItem* aItem, - const nsRect& aRect, nscoord aRadii[8]) - : nsDisplayClip(aBuilder, aFrame, aItem, aRect) -{ - MOZ_COUNT_CTOR(nsDisplayClipRoundedRect); - memcpy(mRadii, aRadii, sizeof(mRadii)); -} - -nsDisplayClipRoundedRect::nsDisplayClipRoundedRect( - nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayList* aList, - const nsRect& aRect, nscoord aRadii[8]) - : nsDisplayClip(aBuilder, aFrame, aList, aRect) -{ - MOZ_COUNT_CTOR(nsDisplayClipRoundedRect); - memcpy(mRadii, aRadii, sizeof(mRadii)); -} - -#ifdef NS_BUILD_REFCNT_LOGGING -nsDisplayClipRoundedRect::~nsDisplayClipRoundedRect() -{ - MOZ_COUNT_DTOR(nsDisplayClipRoundedRect); -} -#endif - -nsRegion -nsDisplayClipRoundedRect::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, - bool* aSnap) -{ - *aSnap = false; - return nsRegion(); -} - -void -nsDisplayClipRoundedRect::HitTest(nsDisplayListBuilder* aBuilder, - const nsRect& aRect, HitTestState* aState, - nsTArray *aOutFrames) -{ - if (!RoundedRectIntersectsRect(mClip, mRadii, aRect)) { - // aRect doesn't intersect our border-radius curve. - - // FIXME: This isn't quite sufficient for aRect having nontrivial - // size (which is the unusual case here), since it's possible that - // the part of aRect that intersects the the rounded rect isn't the - // part that intersects the items in mList. - return; - } - - mList.HitTest(aBuilder, aRect, aState, aOutFrames); -} - -nsDisplayWrapList* -nsDisplayClipRoundedRect::WrapWithClone(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem) { - return new (aBuilder) - nsDisplayClipRoundedRect(aBuilder, aItem->GetUnderlyingFrame(), aItem, - mClip, mRadii); -} - -bool nsDisplayClipRoundedRect::ComputeVisibility( - nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion, - const nsRect& aAllowVisibleRegionExpansion) -{ - nsRegion clipped; - clipped.And(*aVisibleRegion, mClip); - - return nsDisplayWrapList::ComputeVisibility(aBuilder, &clipped, nsRect()); - // FIXME: Remove a *conservative* opaque region from aVisibleRegion - // (like in nsDisplayClip::ComputeVisibility). -} - -bool nsDisplayClipRoundedRect::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) -{ - if (aItem->GetType() != TYPE_CLIP_ROUNDED_RECT) - return false; - nsDisplayClipRoundedRect* other = - static_cast(aItem); - if (!mClip.IsEqualInterior(other->mClip) || - memcmp(mRadii, other->mRadii, sizeof(mRadii)) != 0) - return false; - // No need to track merged frames for clipping - MergeFrom(other); - return true; -} - nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, int32_t aAPD, int32_t aParentAPD, @@ -3399,8 +3238,10 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder, const nsRect& aAllowVisibleRegionExpansion) { // Convert the passed in visible region to our appunits. - nsRegion visibleRegion = - aVisibleRegion->ConvertAppUnitsRoundOut(mParentAPD, mAPD); + nsRegion visibleRegion; + // mVisibleRect has been clipped to GetClippedBounds + visibleRegion.And(*aVisibleRegion, mVisibleRect); + visibleRegion = visibleRegion.ConvertAppUnitsRoundOut(mParentAPD, mAPD); nsRegion originalVisibleRegion = visibleRegion; nsRect transformedVisibleRect = @@ -3408,7 +3249,7 @@ bool nsDisplayZoom::ComputeVisibility(nsDisplayListBuilder *aBuilder, nsRect allowExpansion = aAllowVisibleRegionExpansion.ConvertAppUnitsRoundIn(mParentAPD, mAPD); bool retval = - mList.ComputeVisibilityForSublist(aBuilder, this, &visibleRegion, + mList.ComputeVisibilityForSublist(aBuilder, &visibleRegion, transformedVisibleRect, allowExpansion); @@ -3507,6 +3348,7 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame MOZ_COUNT_CTOR(nsDisplayTransform); NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); NS_ABORT_IF_FALSE(!aFrame->IsTransformed(), "Can't specify a transform getter for a transformed frame!"); + mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); } nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, @@ -3521,6 +3363,7 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame mReferenceFrame = aBuilder->FindReferenceFrameFor(GetTransformRootFrame(aFrame)); mToReferenceFrame = aFrame->GetOffsetToCrossDoc(mReferenceFrame); + mStoredList.SetClip(aBuilder, DisplayItemClip::NoClip()); } /* Returns the delta specified by the -moz-transform-origin property. @@ -4224,6 +4067,9 @@ nsDisplayTransform::TryMerge(nsDisplayListBuilder *aBuilder, if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent()) return false; + if (aItem->GetClip() != GetClip()) + return false; + /* Now, move everything over to this frame and signal that * we merged things! */ @@ -4419,7 +4265,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, this, &childrenVisible, r, nsRect()); + mList.ComputeVisibilityForSublist(aBuilder, &childrenVisible, r, nsRect()); return true; } @@ -4432,6 +4278,8 @@ bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem // aItem->GetUnderlyingFrame() returns non-null because it's nsDisplaySVGEffects if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent()) return false; + if (aItem->GetClip() != GetClip()) + return false; nsDisplaySVGEffects* other = static_cast(aItem); MergeFromTrackingMergedFrames(other); mEffectsBounds.UnionRect(mEffectsBounds, diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 542073bc97dd..d1e55f7eef58 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -112,6 +112,7 @@ class nsDisplayListBuilder { public: typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor; typedef mozilla::FrameLayerBuilder FrameLayerBuilder; + typedef mozilla::DisplayItemClip DisplayItemClip; typedef mozilla::DisplayListClipState DisplayListClipState; typedef nsIWidget::ThemeGeometry ThemeGeometry; @@ -490,7 +491,6 @@ public: public: AutoBuildingDisplayList(nsDisplayListBuilder* aBuilder, bool aIsRoot) : mBuilder(aBuilder), - mPrevClipState(aBuilder->mClipState), mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame), mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame), mPrevCachedOffset(aBuilder->mCachedOffset), @@ -501,7 +501,6 @@ public: nsIFrame* aForChild, bool aIsRoot, bool aIsInFixedPosition) : mBuilder(aBuilder), - mPrevClipState(aBuilder->mClipState), mPrevCachedOffsetFrame(aBuilder->mCachedOffsetFrame), mPrevCachedReferenceFrame(aBuilder->mCachedReferenceFrame), mPrevCachedOffset(aBuilder->mCachedOffset), @@ -522,7 +521,6 @@ public: } } ~AutoBuildingDisplayList() { - mBuilder->mClipState = mPrevClipState; mBuilder->mCachedOffsetFrame = mPrevCachedOffsetFrame; mBuilder->mCachedReferenceFrame = mPrevCachedReferenceFrame; mBuilder->mCachedOffset = mPrevCachedOffset; @@ -531,7 +529,6 @@ public: } private: nsDisplayListBuilder* mBuilder; - DisplayListClipState mPrevClipState; const nsIFrame* mPrevCachedOffsetFrame; const nsIFrame* mPrevCachedReferenceFrame; nsPoint mPrevCachedOffset; @@ -706,6 +703,7 @@ protected: class nsDisplayItem : public nsDisplayItemLink { public: typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters; + typedef mozilla::DisplayItemClip DisplayItemClip; typedef mozilla::layers::FrameMetrics::ViewID ViewID; typedef mozilla::layers::Layer Layer; typedef mozilla::layers::LayerManager LayerManager; @@ -715,21 +713,19 @@ public: // need to count constructors and destructors. nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : mFrame(aFrame) + , mClip(aBuilder->ClipState().GetCurrentCombinedClip(aBuilder)) #ifdef MOZ_DUMP_PAINTING , mPainted(false) #endif { - if (aFrame) { - mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame); - mToReferenceFrame = aBuilder->ToReferenceFrame(aFrame); - } else { - mReferenceFrame = nullptr; - } + 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) #ifdef MOZ_DUMP_PAINTING @@ -737,7 +733,25 @@ public: #endif { } - virtual ~nsDisplayItem() {} + /** + * This constructor is only used in rare cases when we need to construct + * temporary items. + */ + nsDisplayItem(nsIFrame* aFrame) + : mFrame(aFrame) + , mClip(nullptr) + , mReferenceFrame(nullptr) +#ifdef MOZ_DUMP_PAINTING + , mPainted(false) +#endif + { + } + virtual ~nsDisplayItem() + { + if (mClip) { + mClip->MaybeDestroy(); + } + } void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) CPP_THROW_NEW { @@ -774,19 +788,15 @@ public: */ virtual Type GetType() = 0; /** - * If this returns a non-zero value, then pairing this with the - * GetUnderlyingFrame() pointer gives a key that uniquely identifies - * this display item in the display item tree. - * This will only return a zero value for items which wrap display lists - * and do not create a CSS stacking context, therefore requiring - * display items to be individually wrapped --- currently nsDisplayClip - * and nsDisplayClipRoundedRect only. + * Pairing this with the GetUnderlyingFrame() pointer gives a key that + * uniquely identifies this display item in the display item tree. + * XXX check ScrollLayerWrapper/nsOptionEventGrabberWrapper/nsXULEventRedirectorWrapper */ virtual uint32_t GetPerFrameKey() { return uint32_t(GetType()); } /** * This is called after we've constructed a display list for event handling. * When this is called, we've already ensured that aRect intersects the - * item's bounds. + * item's bounds and that clipping has been taking into account. * * @param aRect the point or rect being tested, relative to the reference * frame. If the width and height are both 1 app unit, it indicates we're @@ -800,9 +810,8 @@ public: HitTestState* aState, nsTArray *aOutFrames) {} /** * @return the frame that this display item is based on. This is used to sort - * items by z-index and content order and for some other uses. For some items - * that wrap item lists, this could return nullptr because there is no single - * underlying frame; for leaf items it will never return nullptr. + * items by z-index and content order and for some other uses. Never + * returns null. */ inline nsIFrame* GetUnderlyingFrame() const { return mFrame; } /** @@ -812,6 +821,7 @@ public: * It might be set to false and snap anyway, so code computing the set of * pixels affected by this display item needs to round outwards to pixel * boundaries when *aSnap is set to false. + * This does not take the item's clipping into account. * @return a rectangle relative to aBuilder->ReferenceFrame() that * contains the area drawn by this display item */ @@ -820,6 +830,12 @@ public: *aSnap = false; return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize()); } + /** + * Returns the result of GetBounds intersected with the item's clip. + * The intersection is approximate since rounded corners are not taking into + * account. + */ + nsRect GetClippedBounds(nsDisplayListBuilder* aBuilder); nsRect GetBorderRect() { return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize()); } @@ -926,6 +942,7 @@ public: * color. This is useful for determining when one piece * of content completely obscures another so that we can do occlusion * culling. + * This does not take clipping into account. */ virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, bool* aSnap) @@ -1095,6 +1112,7 @@ public: * return the list. */ virtual nsDisplayList* GetSameCoordinateSystemChildren() { return nullptr; } + virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) {} /** * If this has a child list, return it, even if the children are in @@ -1169,14 +1187,32 @@ public: virtual bool SupportsOptimizingToImage() { return false; } + const DisplayItemClip& GetClip() + { + return mClip ? *mClip : DisplayItemClip::NoClip(); + } + void SetClip(nsDisplayListBuilder* aBuilder, const DisplayItemClip& aClip) + { + if (mClip) { + mClip->MaybeDestroy(); + } + if (!aClip.HasClip()) { + mClip = nullptr; + return; + } + void* mem = aBuilder->Allocate(sizeof(DisplayItemClip)); + DisplayItemClip* clip = new (mem) DisplayItemClip(); + *clip = aClip; + mClip = clip; + } + protected: friend class nsDisplayList; - nsDisplayItem() { - mAbove = nullptr; - } + nsDisplayItem() { mAbove = nullptr; } nsIFrame* mFrame; + const DisplayItemClip* mClip; // Result of FindReferenceFrameFor(mFrame), if mFrame is non-null const nsIFrame* mReferenceFrame; // Result of ToReferenceFrame(mFrame), if mFrame is non-null @@ -1385,7 +1421,6 @@ public: * @return true if any item in the list is visible. */ bool ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aForItem, nsRegion* aVisibleRegion, const nsRect& aListVisibleBounds, const nsRect& aAllowVisibleRegionExpansion); @@ -1481,9 +1516,6 @@ private: // Utility function used to massage the list during ComputeVisibility. void FlattenTo(nsTArray* aElements); - // Utility function used to massage the list during sorting, to rewrite - // any wrapper items with null GetUnderlyingFrame - void ExplodeAnonymousChildLists(nsDisplayListBuilder* aBuilder); nsDisplayItemLink mSentinel; nsDisplayItemLink* mTop; @@ -2223,7 +2255,7 @@ public: /** * Call this if the wrapped list is changed. */ - void UpdateBounds(nsDisplayListBuilder* aBuilder) + virtual void UpdateBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE { mBounds = mList.GetBounds(aBuilder); } @@ -2571,87 +2603,6 @@ public: virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; }; -/** - * nsDisplayClip can clip a list of items, but we take a single item - * initially and then later merge other items into it when we merge - * adjacent matching nsDisplayClips - */ -class nsDisplayClip : public nsDisplayWrapList { -public: - /** - * @param aFrame the frame that should be considered the underlying - * frame for this content, e.g. the frame whose z-index we have. This - * is *not* the frame that is inducing the clipping. - */ - nsDisplayClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayItem* aItem, const nsRect& aRect); - nsDisplayClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayList* aList, const nsRect& aRect); -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayClip(); -#endif - - virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE; - virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; - virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion, - const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; - virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; - NS_DISPLAY_DECL_NAME("Clip", TYPE_CLIP) - virtual uint32_t GetPerFrameKey() { return 0; } - - const nsRect& GetClipRect() { return mClip; } - void SetClipRect(const nsRect& aRect) { mClip = aRect; } - - virtual nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem) MOZ_OVERRIDE; - -protected: - nsRect mClip; -}; - -/** - * A display item to clip a list of items to the border-radius of a - * frame. - */ -class nsDisplayClipRoundedRect : public nsDisplayClip { -public: - /** - * @param aFrame the frame that should be considered the underlying - * frame for this content, e.g. the frame whose z-index we have. This - * is *not* the frame that is inducing the clipping. - */ - nsDisplayClipRoundedRect(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayItem* aItem, - const nsRect& aRect, nscoord aRadii[8]); - nsDisplayClipRoundedRect(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayList* aList, - const nsRect& aRect, nscoord aRadii[8]); -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayClipRoundedRect(); -#endif - - virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder, - bool* aSnap) MOZ_OVERRIDE; - virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, - HitTestState* aState, nsTArray *aOutFrames) MOZ_OVERRIDE; - virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion, - const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; - virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE; - NS_DISPLAY_DECL_NAME("ClipRoundedRect", TYPE_CLIP_ROUNDED_RECT) - - virtual nsDisplayWrapList* WrapWithClone(nsDisplayListBuilder* aBuilder, - nsDisplayItem* aItem); - - void GetRadii(nscoord aRadii[8]) { - memcpy(aRadii, mRadii, sizeof(mRadii)); - } - -private: - nscoord mRadii[8]; -}; - /** * nsDisplayZoom is used for subdocuments that have a different full zoom than * their parent documents. This item creates a container layer. @@ -3001,7 +2952,7 @@ public: : nsDisplayItem(aBuilder, aFrame), mLeftEdge(0), mRightEdge(0) {} nsCharClipDisplayItem(nsIFrame* aFrame) - : nsDisplayItem(nullptr, aFrame, nullptr, nsPoint()) {} + : nsDisplayItem(aFrame) {} struct ClipEdges { ClipEdges(const nsDisplayItem& aItem, diff --git a/layout/base/nsLayoutDebugger.cpp b/layout/base/nsLayoutDebugger.cpp index 702081d75f84..a2d511054e69 100644 --- a/layout/base/nsLayoutDebugger.cpp +++ b/layout/base/nsLayoutDebugger.cpp @@ -15,6 +15,7 @@ #include +using namespace mozilla; using namespace mozilla::layers; #ifdef DEBUG @@ -147,20 +148,11 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList, #endif bool snap; nsRect rect = i->GetBounds(aBuilder, &snap); - switch (i->GetType()) { - case nsDisplayItem::TYPE_CLIP: - case nsDisplayItem::TYPE_CLIP_ROUNDED_RECT: { - nsDisplayClip* c = static_cast(i); - rect = c->GetClipRect(); - break; - } - default: - break; - } nscolor color; nsRect vis = i->GetVisibleRect(); nsRect component = i->GetComponentAlphaBounds(aBuilder); nsDisplayList* list = i->GetChildren(); + const DisplayItemClip& clip = i->GetClip(); nsRegion opaque; #ifdef DEBUG if (!list || list->DidComputeVisibility()) { @@ -173,15 +165,16 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList, string.AppendInt((uint64_t)i); fprintf(aOutput, "", string.BeginReading()); } - fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)(%d,%d,%d,%d)(%d,%d,%d,%d)%s", + fprintf(aOutput, "%s %p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s", i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(), rect.x, rect.y, rect.width, rect.height, vis.x, vis.y, vis.width, vis.height, component.x, component.y, component.width, component.height, + clip.ToString().get(), i->IsUniform(aBuilder, &color) ? " uniform" : ""); nsRegionRectIterator iter(opaque); for (const nsRect* r = iter.Next(); r; r = iter.Next()) { - fprintf(aOutput, "(opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height); + fprintf(aOutput, " (opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height); } i->WriteDebugInfo(aOutput); if (aDumpHtml && i->Painted()) { diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 1643ab8e90f5..6b06adf849b9 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -4500,10 +4500,9 @@ PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder, // determined. To do this, remove an item from the bottom of the list, check // whether it should be part of the range, and if so, append it to the top // of the temporary list tmpList. If the item is a text frame at the end of - // the selection range, wrap it in an nsDisplayClip to clip the display to - // the portion of the text frame that is part of the selection. Then, append - // the wrapper to the top of the list. Otherwise, just delete the item and - // don't append it. + // the selection range, clip it to the portion of the text frame that is + // part of the selection. Then, append the wrapper to the top of the list. + // Otherwise, just delete the item and don't append it. nsRect surfaceRect; nsDisplayList tmpList; @@ -4542,11 +4541,11 @@ PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder, textRect.width = std::max(startPoint.x, endPoint.x) - x; surfaceRect.UnionRect(surfaceRect, textRect); - // wrap the item in an nsDisplayClip so that it can be clipped to - // the selection. If the allocation fails, fall through and delete - // the item below. - itemToInsert = new (aBuilder) - nsDisplayClip(aBuilder, frame, i, textRect); + DisplayItemClip newClip; + newClip.SetTo(textRect); + newClip.IntersectWith(i->GetClip()); + i->SetClip(aBuilder, newClip); + itemToInsert = i; } } // Don't try to descend into subdocuments. diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index dadfb039cd59..aac960d5b74d 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -351,20 +351,26 @@ nsFileControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayBoxShadowOuter(aBuilder, this)); } - // Our background is inherited to the text input, and we don't really want to - // paint it or out padding and borders (which we never have anyway, per - // styles in forms.css) -- doing it just makes us look ugly in some cases and - // has no effect in others. - nsDisplayListCollection tempList; - nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, tempList); - - tempList.BorderBackground()->DeleteAll(); - // Clip height only nsRect clipRect(aBuilder->ToReferenceFrame(this), GetSize()); clipRect.width = GetVisualOverflowRect().XMost(); - nscoord radii[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - OverflowClip(aBuilder, tempList, aLists, clipRect, radii); + + nsDisplayListCollection tempList; + { + DisplayListClipState::AutoSaveRestore saveClipState(aBuilder->ClipState()); + DisplayItemClip clipOnStack; + aBuilder->ClipState().ClipContainingBlockDescendants(clipRect, nullptr, clipOnStack); + + // Our background is inherited to the text input, and we don't really want to + // paint it or out padding and borders (which we never have anyway, per + // styles in forms.css) -- doing it just makes us look ugly in some cases and + // has no effect in others. + nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, tempList); + } + + tempList.BorderBackground()->DeleteAll(); + + tempList.MoveTo(aLists); // Disabled file controls don't pass mouse events to their children, so we // put an invisible item in the display list above the children diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp index b0bf5b2a181f..2a02a0f1fb7f 100644 --- a/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/layout/forms/nsHTMLButtonControlFrame.cpp @@ -116,31 +116,37 @@ nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, if (IsVisibleForPainting(aBuilder)) { mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop); } - + + bool overflowClip = + IsInput() || StyleDisplay()->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE; + nsRect rect; + nscoord radii[8]; nsDisplayListCollection set; - // Do not allow the child subtree to receive events. - if (!aBuilder->IsForEventDelivery()) { - BuildDisplayListForChild(aBuilder, mFrames.FirstChild(), aDirtyRect, set, - DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT); - // That should put the display items in set.Content() + + { + DisplayListClipState::AutoSaveRestore saveClipState(aBuilder->ClipState()); + DisplayItemClip overflowClipOnStack; + + if (overflowClip) { + nsMargin border = StyleBorder()->GetComputedBorder(); + rect = nsRect(aBuilder->ToReferenceFrame(this), GetSize()); + rect.Deflate(border); + bool hasRadii = GetPaddingBoxBorderRadii(radii); + aBuilder->ClipState().ClipContainingBlockDescendants(rect, + hasRadii ? radii : nullptr, overflowClipOnStack); + } + + // Do not allow the child subtree to receive events. + if (!aBuilder->IsForEventDelivery()) { + BuildDisplayListForChild(aBuilder, mFrames.FirstChild(), aDirtyRect, set, + DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT); + // That should put the display items in set.Content() + } } // Put the foreground outline and focus rects on top of the children set.Content()->AppendToTop(&onTop); - - // clips to our padding box for s but not