Bug 841192. Part 14: Convert all usage of nsDisplayClip(RoundedRect) to use DisplayListClipState/DisplayItemClip. r=mattwoodrow

This patch does several things. Sorry.

In BuildDisplayList implementations, instead of wrapping display items in nsDisplayClip, we
push clip state onto the nsDisplayListBuilder and give the display items an
explicit clip when they're created.

In FrameLayerBuilder, we use the explicit clips we find on display items instead of
computing our own.

We remove nsDisplayClip and everything that depends on it.

We remove ExplodeAnonymousChildLists. With nsDisplayClip gone, and
nsDisplayOptionEventGrabber removed in a previous patch, there are no
anonymous child lists.

nsDisplayItem::TryMerge implementations need to make sure they have the same
clip before being merged.

I ripped out the part of PruneDisplayListForExtraPage that adjusts clip rects.
As far as I can tell, it isn't actually necessary.
This commit is contained in:
Robert O'Callahan
2013-03-04 22:56:02 +13:00
parent f9819ba6db
commit 29d310bf8a
22 changed files with 581 additions and 989 deletions

View File

@@ -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<nsDisplayItemGeometry> 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<nsDisplayItemGeometry> 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<nsRenderingContext> 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.");

View File

@@ -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<LayerManager> mInactiveLayerManager;
DisplayItemClip mClip;
uint32_t mContainerLayerGeneration;
};

View File

@@ -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)

View File

@@ -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,8 +931,16 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
opaque = aItem->GetBounds(aBuilder, &snap);
}
}
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
GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
@@ -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<nsIFrame*, 16> 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<nsDisplayWrapList*>(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,
// 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<nsDisplayOpacity*>(aItem));
return true;
}
@@ -2948,6 +2940,8 @@ bool nsDisplayFixedPosition::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayI
nsDisplayFixedPosition* other = static_cast<nsDisplayFixedPosition*>(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<nsDisplayScrollLayer*>(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<nsDisplayClip*>(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<nsIFrame*> *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<nsDisplayClipRoundedRect*>(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<nsDisplaySVGEffects*>(aItem);
MergeFromTrackingMergedFrames(other);
mEffectsBounds.UnionRect(mEffectsBounds,

View File

@@ -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;
}
}
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<nsIFrame*> *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<nsDisplayItem*>* 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<nsIFrame*> *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,

View File

@@ -15,6 +15,7 @@
#include <stdio.h>
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<nsDisplayClip*>(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,11 +165,12 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
string.AppendInt((uint64_t)i);
fprintf(aOutput, "<a href=\"javascript:ViewImage('%s')\">", 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()) {

View File

@@ -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.

View File

@@ -351,20 +351,26 @@ nsFileControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsDisplayBoxShadowOuter(aBuilder, this));
}
// Clip height only
nsRect clipRect(aBuilder->ToReferenceFrame(this), GetSize());
clipRect.width = GetVisualOverflowRect().XMost();
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.
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);
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

View File

@@ -117,30 +117,36 @@ nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop);
}
bool overflowClip =
IsInput() || StyleDisplay()->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE;
nsRect rect;
nscoord radii[8];
nsDisplayListCollection set;
{
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 <input>s but not <button>s, unless
// they have non-visible overflow..
if (IsInput() || StyleDisplay()->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE) {
nsMargin border = StyleBorder()->GetComputedBorder();
nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
rect.Deflate(border);
nscoord radii[8];
GetPaddingBoxBorderRadii(radii);
OverflowClip(aBuilder, set, aLists, rect, radii);
} else {
set.MoveTo(aLists);
}
DisplayOutline(aBuilder, aLists);

View File

@@ -101,31 +101,28 @@ IsHorizontalOverflowVisible(nsIFrame* aFrame)
return !f || f->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE;
}
static nsDisplayItem*
static void
ClipMarker(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
nsDisplayItem* aMarker,
const nsRect& aContentArea,
nsRect* aMarkerRect)
const nsRect& aMarkerRect,
DisplayItemClip& aClipOnStack)
{
nsDisplayItem* item = aMarker;
nscoord rightOverflow = aMarkerRect->XMost() - aContentArea.XMost();
nscoord rightOverflow = aMarkerRect.XMost() - aContentArea.XMost();
nsRect markerRect = aMarkerRect;
if (rightOverflow > 0) {
// Marker overflows on the right side (content width < marker width).
aMarkerRect->width -= rightOverflow;
item = new (aBuilder)
nsDisplayClip(aBuilder, aFrame, aMarker, *aMarkerRect);
markerRect.width -= rightOverflow;
aBuilder->ClipState().ClipContentDescendants(markerRect, aClipOnStack);
} else {
nscoord leftOverflow = aContentArea.x - aMarkerRect->x;
nscoord leftOverflow = aContentArea.x - aMarkerRect.x;
if (leftOverflow > 0) {
// Marker overflows on the left side
aMarkerRect->width -= leftOverflow;
aMarkerRect->x += leftOverflow;
item = new (aBuilder)
nsDisplayClip(aBuilder, aFrame, aMarker, *aMarkerRect);
markerRect.width -= leftOverflow;
markerRect.x += leftOverflow;
aBuilder->ClipState().ClipContentDescendants(markerRect, aClipOnStack);
}
}
return item;
}
static void
@@ -711,34 +708,36 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine,
const nsRect& aInsideMarkersArea)
{
if (aCreateLeft) {
DisplayListClipState::AutoSaveRestore saveClip(mBuilder->ClipState());
nsRect markerRect = nsRect(aInsideMarkersArea.x - mLeft.mIntrinsicWidth,
aLine->mBounds.y,
mLeft.mIntrinsicWidth, aLine->mBounds.height);
markerRect += mBuilder->ToReferenceFrame(mBlock);
DisplayItemClip clipOnStack;
ClipMarker(mBuilder, mBlock,
mContentArea + mBuilder->ToReferenceFrame(mBlock),
markerRect, clipOnStack);
nsDisplayItem* marker = new (mBuilder)
nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
aLine->GetAscent(), mLeft.mStyle, 0);
if (marker) {
marker = ClipMarker(mBuilder, mBlock, marker,
mContentArea + mBuilder->ToReferenceFrame(mBlock),
&markerRect);
}
mMarkerList.AppendNewToTop(marker);
}
if (aCreateRight) {
DisplayListClipState::AutoSaveRestore saveClip(mBuilder->ClipState());
nsRect markerRect = nsRect(aInsideMarkersArea.XMost(),
aLine->mBounds.y,
mRight.mIntrinsicWidth, aLine->mBounds.height);
markerRect += mBuilder->ToReferenceFrame(mBlock);
DisplayItemClip clipOnStack;
ClipMarker(mBuilder, mBlock,
mContentArea + mBuilder->ToReferenceFrame(mBlock),
markerRect, clipOnStack);
nsDisplayItem* marker = new (mBuilder)
nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
aLine->GetAscent(), mRight.mStyle, 1);
if (marker) {
marker = ClipMarker(mBuilder, mBlock, marker,
mContentArea + mBuilder->ToReferenceFrame(mBlock),
&markerRect);
}
mMarkerList.AppendNewToTop(marker);
}
}

View File

@@ -346,16 +346,6 @@ nsIFrame::FindCloserFrameForSelection(
}
}
static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
const nsIFrame* aFrame,
const nsStyleDisplay* aDisp,
nsRect* aRect);
static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
const nsStyleDisplay* aDisp,
const nsIFrame* aFrame,
nsRect* aRect);
void
NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary)
{
@@ -1032,9 +1022,10 @@ nsIFrame::Preserves3DChildren() const
return false;
nsRect temp;
return (!ApplyOverflowClipping(nullptr, this, StyleDisplay(), &temp) &&
!ApplyClipPropClipping(nullptr, StyleDisplay(), this, &temp) &&
!nsSVGIntegrationUtils::UsingEffectsForFrame(this));
const nsStyleDisplay* displayStyle = StyleDisplay();
return !nsFrame::ShouldApplyOverflowClipping(this, displayStyle) &&
!GetClipPropClipRect(displayStyle, &temp, GetSize()) &&
!nsSVGIntegrationUtils::UsingEffectsForFrame(this);
}
bool
@@ -1580,144 +1571,52 @@ nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
return true;
}
static bool ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
const nsStyleDisplay* aDisp, const nsIFrame* aFrame,
nsRect* aRect) {
/**
* If the CSS 'clip' property applies to this frame, set it up
* in aBuilder->ClipState() to clip all content descendants. Returns true
* if the property applies, and if so also returns the clip rect (relative
* to aFrame) in *aRect.
*/
static bool
ApplyClipPropClipping(nsDisplayListBuilder* aBuilder,
const nsIFrame* aFrame,
const nsStyleDisplay* aDisp,
nsRect* aRect, DisplayItemClip& aClipOnStack)
{
if (!aFrame->GetClipPropClipRect(aDisp, aRect, aFrame->GetSize()))
return false;
if (aBuilder) {
*aRect += aBuilder->ToReferenceFrame(aFrame);
}
nsRect clipRect = *aRect + aBuilder->ToReferenceFrame(aFrame);
aBuilder->ClipState().ClipContentDescendants(clipRect, aClipOnStack);
return true;
}
static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
/**
* If the CSS 'overflow' property applies to this frame, and is not
* handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
* for that overflow in aBuilder->ClipState() to clip all containing-block
* descendants.
*/
static void
ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
const nsIFrame* aFrame,
const nsStyleDisplay* aDisp, nsRect* aRect) {
// REVIEW: from nsContainerFrame.cpp SyncFrameViewGeometryDependentProperties,
// except that that function used the border-edge for
// -moz-hidden-unscrollable which I don't think is correct... Also I've
// changed -moz-hidden-unscrollable to apply to any kind of frame.
const nsStyleDisplay* aDisp,
DisplayItemClip& aClipOnStack)
{
// Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
// frames, and any non-visible value for blocks in a paginated context).
// Other overflow clipping is applied by nsHTML/XULScrollFrame.
// We allow -moz-hidden-unscrollable to apply to any kind of frame. This
// is required by comboboxes which make their display text (an inline frame)
// have clipping.
if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
return false;
return;
}
*aRect = aFrame->GetPaddingRect() - aFrame->GetPosition();
if (aBuilder) {
*aRect += aBuilder->ToReferenceFrame(aFrame);
}
return true;
}
class nsOverflowClipWrapper : public nsDisplayWrapper
{
public:
/**
* Create a wrapper to apply overflow clipping for aContainer.
* @param aClipBorderBackground set to true to clip the BorderBackground()
* list, otherwise it will not be clipped
* @param aClipAll set to true to clip all descendants, even those for
* which we aren't the containing block
*/
nsOverflowClipWrapper(nsIFrame* aContainer, const nsRect& aRect,
const nscoord aRadii[8],
bool aClipBorderBackground, bool aClipAll)
: mContainer(aContainer), mRect(aRect),
mClipBorderBackground(aClipBorderBackground), mClipAll(aClipAll),
mHaveRadius(false)
{
memcpy(mRadii, aRadii, sizeof(mRadii));
NS_FOR_CSS_HALF_CORNERS(corner) {
if (aRadii[corner] > 0) {
mHaveRadius = true;
break;
}
}
}
virtual bool WrapBorderBackground() { return mClipBorderBackground; }
virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList) {
// We are not a stacking context root. There is no valid underlying
// frame for the whole list. These items are all in-flow descendants so
// we can safely just clip them.
if (mHaveRadius) {
return new (aBuilder) nsDisplayClipRoundedRect(aBuilder, nullptr, aList,
mRect, mRadii);
}
return new (aBuilder) nsDisplayClip(aBuilder, nullptr, aList, mRect);
}
virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem) {
nsIFrame* f = aItem->GetUnderlyingFrame();
if (mClipAll ||
nsLayoutUtils::IsProperAncestorFrame(mContainer, f, nullptr)) {
if (mHaveRadius) {
return new (aBuilder) nsDisplayClipRoundedRect(aBuilder, f, aItem,
mRect, mRadii);
}
return new (aBuilder) nsDisplayClip(aBuilder, f, aItem, mRect);
}
return aItem;
}
protected:
nsIFrame* mContainer;
nsRect mRect;
nscoord mRadii[8];
bool mClipBorderBackground;
bool mClipAll;
bool mHaveRadius;
};
class nsDisplayClipPropWrapper : public nsDisplayWrapper
{
public:
nsDisplayClipPropWrapper(const nsRect& aRect)
: mRect(aRect) {}
virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame, nsDisplayList* aList) {
// We are not a stacking context root. There is no valid underlying
// frame for the whole list.
return new (aBuilder) nsDisplayClip(aBuilder, nullptr, aList, mRect);
}
virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem) {
return new (aBuilder) nsDisplayClip(aBuilder, aItem->GetUnderlyingFrame(),
aItem, mRect);
}
protected:
nsRect mRect;
};
nsresult
nsIFrame::OverflowClip(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aFromSet,
const nsDisplayListSet& aToSet,
const nsRect& aClipRect,
const nscoord aClipRadii[8],
bool aClipBorderBackground,
bool aClipAll)
{
nsOverflowClipWrapper wrapper(this, aClipRect, aClipRadii,
aClipBorderBackground, aClipAll);
return wrapper.WrapLists(aBuilder, this, aFromSet, aToSet);
}
static void
BuildDisplayListWithOverflowClip(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsRect& aDirtyRect, const nsDisplayListSet& aSet,
const nsRect& aClipRect, const nscoord aClipRadii[8])
{
nsDisplayListCollection set;
aFrame->BuildDisplayList(aBuilder, aDirtyRect, set);
aBuilder->DisplayCaret(aFrame, aDirtyRect, aSet.Content());
aFrame->OverflowClip(aBuilder, set, aSet, aClipRect, aClipRadii);
nsRect rect = aFrame->GetPaddingRectRelativeToSelf() +
aBuilder->ToReferenceFrame(aFrame);
nscoord radii[8];
bool haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
aBuilder->ClipState().ClipContainingBlockDescendants(rect,
haveRadii ? radii : nullptr, aClipOnStack);
}
#ifdef DEBUG
@@ -1853,7 +1752,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
return;
nsRect clipPropClip;
const nsStyleDisplay* disp = StyleDisplay();
// We can stop right away if this is a zero-opacity stacking context and
// we're painting, and we're not animating opacity. Don't do this
@@ -1866,12 +1764,11 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
return;
}
bool applyClipPropClipping =
ApplyClipPropClipping(aBuilder, disp, this, &clipPropClip);
nsRect dirtyRect = aDirtyRect;
bool inTransform = aBuilder->IsInTransform();
if (IsTransformed()) {
bool isTransformed = IsTransformed();
if (isTransformed) {
if (aBuilder->IsForPainting() &&
nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this)) {
dirtyRect = GetVisualOverflowRectRelativeToSelf();
@@ -1902,17 +1799,39 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
inTransform = true;
}
if (applyClipPropClipping) {
dirtyRect.IntersectRect(dirtyRect,
clipPropClip - aBuilder->ToReferenceFrame(this));
bool useOpacity = HasOpacity() && !nsSVGUtils::CanOptimizeOpacity(this);
bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
DisplayListClipState::AutoSaveRestore saveClipState(aBuilder->ClipState());
if (isTransformed || useOpacity || usingSVGEffects) {
// We don't need to pass ancestor clipping down to our children;
// everything goes inside a display item's child list, and the display
// item itself will be clipped.
// For transforms we also need to clear ancestor clipping because it's
// relative to the wrong display item reference frame anyway.
aBuilder->ClipState().Clear();
}
bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
nsDisplayListCollection set;
{
nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, true);
DisplayListClipState::AutoSaveRestore clipState(aBuilder->ClipState());
nsDisplayListBuilder::AutoInTransformSetter
inTransformSetter(aBuilder, inTransform);
if (usingSVGEffects) {
dirtyRect =
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
}
nsRect clipPropClip;
DisplayItemClip clipPropClipOnStack;
if (ApplyClipPropClipping(aBuilder, this, disp, &clipPropClip,
clipPropClipOnStack)) {
dirtyRect.IntersectRect(dirtyRect, clipPropClip);
}
MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
// Preserve3DChildren() also guarantees that applyAbsPosClipping and usingSVGEffects are false
@@ -1921,11 +1840,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
aBuilder->MarkPreserve3DFramesForDisplayList(this, aDirtyRect);
}
nsDisplayListCollection set;
{
nsDisplayListBuilder::AutoBuildingDisplayList rootSetter(aBuilder, true);
nsDisplayListBuilder::AutoInTransformSetter
inTransformSetter(aBuilder, inTransform);
BuildDisplayList(aBuilder, dirtyRect, set);
}
@@ -1945,18 +1859,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
// element itself.
set.PositionedDescendants()->SortByZOrder(aBuilder, GetContent());
nsRect overflowClip;
if (ApplyOverflowClipping(aBuilder, this, disp, &overflowClip)) {
nscoord radii[8];
this->GetPaddingBoxBorderRadii(radii);
nsOverflowClipWrapper wrapper(this, overflowClip, radii,
false, false);
wrapper.WrapListsInPlace(aBuilder, this, set);
}
// We didn't use overflowClip to restrict the dirty rect, since some of the
// descendants may not be clipped by it. Even if we end up with unnecessary
// display items, they'll be pruned during ComputeVisibility.
nsDisplayList resultList;
// Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
// 1,2: backgrounds and borders
@@ -1994,16 +1896,12 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
// 8, 9: non-negative z-index children
resultList.AppendToTop(set.PositionedDescendants());
/* If we have absolute position clipping and we have, or will have, items to
* be clipped, wrap the list in a clip wrapper.
*/
if (applyClipPropClipping &&
(!resultList.IsEmpty() || usingSVGEffects)) {
nsDisplayClipPropWrapper wrapper(clipPropClip);
nsDisplayItem* item = wrapper.WrapList(aBuilder, this, &resultList);
// resultList was emptied
resultList.AppendNewToTop(item);
if (!isTransformed) {
// Restore saved clip state now so that any display items we create below
// are clipped properly.
saveClipState.Restore();
}
/* If there are any SVG effects, wrap the list up in an SVG effects item
* (which also handles CSS group opacity). Note that we create an SVG effects
* item even if resultList is empty, since a filter can produce graphical
@@ -2017,9 +1915,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
/* Else, if the list is non-empty and there is CSS group opacity without SVG
* effects, wrap it up in an opacity item.
*/
else if (HasOpacity() &&
!nsSVGUtils::CanOptimizeOpacity(this) &&
!resultList.IsEmpty()) {
else if (useOpacity && !resultList.IsEmpty()) {
resultList.AppendNewToTop(
new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
}
@@ -2035,7 +1931,10 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
* We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
* we find all the correct children.
*/
if (IsTransformed() && !resultList.IsEmpty()) {
if (isTransformed && !resultList.IsEmpty()) {
// Restore clip state now so nsDisplayTransform is clipped properly.
saveClipState.Restore();
if (Preserves3DChildren()) {
WrapPreserve3DList(this, aBuilder, &resultList);
} else {
@@ -2117,7 +2016,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
return;
savedOutOfFlowData = static_cast<OutOfFlowDisplayData*>
savedOutOfFlowData = static_cast<nsDisplayListBuilder::OutOfFlowDisplayData*>
(child->Properties().Get(nsDisplayListBuilder::OutOfFlowDisplayDataProperty()));
if (savedOutOfFlowData) {
dirty = savedOutOfFlowData->mDirtyRect;
@@ -2183,11 +2082,16 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Child is composited if it's transformed, partially transparent, or has
// SVG effects.
const nsStyleDisplay* disp = child->StyleDisplay();
const nsStylePosition* pos = child->StylePosition();
bool isVisuallyAtomic = child->HasOpacity()
|| child->IsTransformed()
|| nsSVGIntegrationUtils::UsingEffectsForFrame(child);
bool isPositioned = !isSVG && disp->IsPositioned(child);
bool isStackingContext =
(isPositioned && pos->mZIndex.GetUnit() == eStyleUnit_Integer) ||
isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
((disp->mClipFlags & NS_STYLE_CLIP_RECT) &&
IsSVGContentWithCSSClip(child)) ||
@@ -2195,6 +2099,8 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// If you change this, also change IsPseudoStackingContextFromStyle()
pseudoStackingContext = true;
}
NS_ASSERTION(!isStackingContext || pseudoStackingContext,
"Stacking contexts must also be pseudo-stacking-contexts");
// This controls later whether we build an nsDisplayWrapList or an
// nsDisplayFixedPosition. We check if we're already building a fixed-pos
@@ -2208,26 +2114,44 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
nsDisplayListBuilder::AutoBuildingDisplayList
buildingForChild(aBuilder, child, pseudoStackingContext, buildFixedPositionItem);
DisplayListClipState::AutoSaveRestore clipState(aBuilder->ClipState());
if (savedOutOfFlowData) {
aBuilder->ClipState().SetClipForContainingBlockDescendants(
clipState.SetClipForContainingBlockDescendants(
savedOutOfFlowData->mContainingBlockClip);
}
nsRect overflowClip;
nscoord overflowClipRadii[8];
bool applyOverflowClip =
ApplyOverflowClipping(aBuilder, child, disp, &overflowClip);
if (applyOverflowClip) {
child->GetPaddingBoxBorderRadii(overflowClipRadii);
}
// Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
// or overflow:hidden on elements that don't support scrolling (and therefore
// don't create nsHTML/XULScrollFrame). This clipping needs to not clip
// anything directly rendered by the parent, only the rendering of its
// children.
// Don't use overflowClip to restrict the dirty rect, since some of the
// descendants may not be clipped by it. Even if we end up with unnecessary
// display items, they'll be pruned during ComputeVisibility. Note that
// this overflow-clipping here only applies to overflow:-moz-hidden-unscrollable;
// overflow:hidden etc creates an nsHTML/XULScrollFrame which does its own
// clipping.
// display items, they'll be pruned during ComputeVisibility.
DisplayItemClip overflowClipOnStack;
nsIFrame* parent = child->GetParent();
const nsStyleDisplay* parentDisp =
parent == this ? ourDisp : parent->StyleDisplay();
ApplyOverflowClipping(aBuilder, parent, parentDisp, overflowClipOnStack);
nsDisplayList list;
nsDisplayList extraPositionedDescendants;
if (isStackingContext) {
// True stacking context.
// For stacking contexts, BuildDisplayListForStackingContext handles
// clipping and MarkAbsoluteFramesForDisplayList.
child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
aBuilder->DisplayCaret(child, dirty, &list);
} else {
nsRect clipRect;
DisplayItemClip clipPropClipOnStack;
if (ApplyClipPropClipping(aBuilder, child, disp, &clipRect,
clipPropClipOnStack)) {
// clipRect is in builder-reference-frame coordinates,
// dirty/clippedDirtyRect are in child coordinates
dirty.IntersectRect(dirty, clipRect);
}
child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
@@ -2235,57 +2159,22 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// THIS IS THE COMMON CASE.
// Not a pseudo or real stacking context. Do the simple thing and
// return early.
if (applyOverflowClip) {
BuildDisplayListWithOverflowClip(aBuilder, child, dirty, aLists,
overflowClip, overflowClipRadii);
} else {
child->BuildDisplayList(aBuilder, dirty, aLists);
aBuilder->DisplayCaret(child, dirty, aLists.Content());
}
#ifdef DEBUG
DisplayDebugBorders(aBuilder, child, aLists);
#endif
return;
}
nsDisplayList list;
nsDisplayList extraPositionedDescendants;
const nsStylePosition* pos = child->StylePosition();
if ((isPositioned && pos->mZIndex.GetUnit() == eStyleUnit_Integer) ||
isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
// True stacking context
child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
aBuilder->DisplayCaret(child, dirty, &list);
} else {
nsRect clipRect;
bool applyClipPropClipping =
ApplyClipPropClipping(aBuilder, disp, child, &clipRect);
// A pseudo-stacking context (e.g., a positioned element with z-index auto).
// We allow positioned descendants of the child to escape to our parent
// stacking context's positioned descendant list, because they might be
// z-index:non-auto
nsDisplayListCollection pseudoStack;
nsRect clippedDirtyRect = dirty;
if (applyClipPropClipping) {
// clipRect is in builder-reference-frame coordinates,
// dirty/clippedDirtyRect are in child coordinates
clippedDirtyRect.IntersectRect(clippedDirtyRect,
clipRect - aBuilder->ToReferenceFrame(child));
}
if (applyOverflowClip) {
BuildDisplayListWithOverflowClip(aBuilder, child, clippedDirtyRect,
pseudoStack, overflowClip,
overflowClipRadii);
} else {
child->BuildDisplayList(aBuilder, clippedDirtyRect, pseudoStack);
child->BuildDisplayList(aBuilder, dirty, pseudoStack);
aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
}
if (applyClipPropClipping) {
nsDisplayClipPropWrapper wrapper(clipRect);
wrapper.WrapListsInPlace(aBuilder, child, pseudoStack);
}
list.AppendToTop(pseudoStack.BorderBackground());
list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
list.AppendToTop(pseudoStack.Floats());
@@ -2297,6 +2186,10 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
#endif
}
// Clear clip rect for the construction of the items below. Since we're
// clipping all their contents, they themselves don't need to be clipped.
aBuilder->ClipState().Clear();
if (isPositioned || isVisuallyAtomic ||
(aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
// Genuine stacking contexts, and positioned pseudo-stacking-contexts,
@@ -2353,27 +2246,6 @@ nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder,
}
}
void
nsIFrame::WrapReplacedContentForBorderRadius(nsDisplayListBuilder* aBuilder,
nsDisplayList* aFromList,
const nsDisplayListSet& aToLists)
{
nscoord radii[8];
if (GetContentBoxBorderRadii(radii)) {
// If we have a border-radius, we have to clip our content to that
// radius.
nsDisplayListCollection set;
set.Content()->AppendToTop(aFromList);
nsRect clipRect = GetContentRect() - GetPosition() +
aBuilder->ToReferenceFrame(this);
OverflowClip(aBuilder, set, aToLists, clipRect, radii, false, true);
return;
}
aToLists.Content()->AppendToTop(aFromList);
}
NS_IMETHODIMP
nsFrame::GetContentForEvent(nsEvent* aEvent,
nsIContent** aContent)

View File

@@ -2127,7 +2127,38 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
nsDisplayListCollection set;
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set);
{
DisplayListClipState::AutoSaveRestore saveClipState(aBuilder->ClipState());
DisplayItemClip clipOnStack;
if (usingDisplayport) {
nsRect clip = displayPort + aBuilder->ToReferenceFrame(mOuter);
if (mIsRoot) {
aBuilder->ClipState().ClipContentDescendants(clip, clipOnStack);
} else {
aBuilder->ClipState().ClipContainingBlockDescendants(clip, nullptr, clipOnStack);
}
} else {
nsRect clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
// Our override of GetBorderRadii ensures we never have a radius at
// the corners where we have a scrollbar.
if (mIsRoot) {
#ifdef DEBUG
nscoord radii[8];
#endif
NS_ASSERTION(!mOuter->GetPaddingBoxBorderRadii(radii),
"Roots with radii not supported");
aBuilder->ClipState().ClipContentDescendants(clip, clipOnStack);
} else {
nscoord radii[8];
bool haveRadii = mOuter->GetPaddingBoxBorderRadii(radii);
aBuilder->ClipState().ClipContainingBlockDescendants(clip,
haveRadii ? radii : nullptr, clipOnStack);
}
}
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, aLists);
}
// Since making new layers is expensive, only use nsDisplayScrollLayer
// if the area is scrollable and we're the content process.
@@ -2147,27 +2178,6 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
(!mIsRoot || !mOuter->PresContext()->IsRootContentDocument()));
}
nsRect clip;
nscoord radii[8];
if (usingDisplayport) {
clip = displayPort + aBuilder->ToReferenceFrame(mOuter);
memset(radii, 0, sizeof(nscoord) * ArrayLength(radii));
} else {
clip = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
// Our override of GetBorderRadii ensures we never have a radius at
// the corners where we have a scrollbar.
mOuter->GetPaddingBoxBorderRadii(radii);
}
// mScrolledFrame may have given us a background, e.g., the scrolled canvas
// frame below the viewport. If so, we want it to be clipped. We also want
// to end up on our BorderBackground list.
// If we are the viewport scrollframe, then clip all our descendants (to ensure
// that fixed-pos elements get clipped by us).
mOuter->OverflowClip(aBuilder, set, aLists, clip, radii,
true, mIsRoot);
if (ShouldBuildLayer()) {
// ScrollLayerWrapper must always be created because it initializes the
// scroll layer count. The display lists depend on this.

View File

@@ -290,15 +290,14 @@ nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
DisplayBorderBackgroundOutline(aBuilder, aLists);
nsDisplayList replacedContent;
DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT);
replacedContent.AppendNewToTop(
aLists.Content()->AppendNewToTop(
new (aBuilder) nsDisplayCanvas(aBuilder, this));
DisplaySelectionOverlay(aBuilder, &replacedContent,
DisplaySelectionOverlay(aBuilder, aLists.Content(),
nsISelectionDisplay::DISPLAY_IMAGES);
WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
}
nsIAtom*

View File

@@ -1205,25 +1205,6 @@ public:
const nsRect& aDirtyRect,
nsDisplayList* aList);
/**
* Clips the display items of aFromSet, putting the results in aToSet.
* Only items corresponding to frames which are descendants of this frame
* are clipped. In other words, descendant elements whose CSS boxes do not
* have this frame as a container are not clipped. Also,
* border/background/outline items for this frame are not clipped,
* unless aClipBorderBackground is set to true. (We need this because
* a scrollframe must overflow-clip its scrolled child's background/borders.)
*
* Indices into aClipRadii are the NS_CORNER_* constants in nsStyleConsts.h
*/
nsresult OverflowClip(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aFromSet,
const nsDisplayListSet& aToSet,
const nsRect& aClipRect,
const nscoord aClipRadii[8],
bool aClipBorderBackground = false,
bool aClipAll = false);
enum {
DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT = 0x01,
DISPLAY_CHILD_FORCE_STACKING_CONTEXT = 0x02,
@@ -1244,15 +1225,6 @@ public:
const nsDisplayListSet& aLists,
uint32_t aFlags = 0);
/**
* A helper for replaced elements that want to clip their content to a
* border radius, but only need clipping at all when they have a
* border radius.
*/
void WrapReplacedContentForBorderRadius(nsDisplayListBuilder* aBuilder,
nsDisplayList* aFromList,
const nsDisplayListSet& aToLists);
/**
* Does this frame need a view?
*/

View File

@@ -1365,16 +1365,11 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (!IsVisibleForPainting(aBuilder))
return;
// REVIEW: We don't need any special logic here for deciding which layer
// to put the background in ... it goes in aLists.BorderBackground() and
// then if we have a block parent, it will put our background in the right
// place.
DisplayBorderBackgroundOutline(aBuilder, aLists);
// REVIEW: Checking mRect.IsEmpty() makes no sense to me, so I removed it.
// It can't have been protecting us against bad situations with zero-size
// images since adding a border would make the rect non-empty.
nsDisplayList replacedContent;
DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT);
if (mComputedSize.width != 0 && mComputedSize.height != 0) {
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
NS_ASSERTION(imageLoader, "Not an image loading content?");
@@ -1407,11 +1402,11 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (!imageOK || !haveSize) {
// No image yet, or image load failed. Draw the alt-text and an icon
// indicating the status
replacedContent.AppendNewToTop(new (aBuilder)
aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayAltFeedback(aBuilder, this));
}
else {
replacedContent.AppendNewToTop(new (aBuilder)
aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayImage(aBuilder, this, imgCon));
// If we were previously displaying an icon, we're not anymore
@@ -1420,7 +1415,6 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mDisplayingIcon = false;
}
#ifdef DEBUG
if (GetShowFrameBorders() && GetImageMap()) {
aLists.Outlines()->AppendNewToTop(new (aBuilder)
@@ -1432,11 +1426,9 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
if (ShouldDisplaySelection()) {
DisplaySelectionOverlay(aBuilder, &replacedContent,
DisplaySelectionOverlay(aBuilder, aLists.Content(),
nsISelectionDisplay::DISPLAY_IMAGES);
}
WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
}
bool

View File

@@ -1229,8 +1229,6 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
#endif
nsDisplayList replacedContent;
if (aBuilder->IsForPainting() && mInstanceOwner && mInstanceOwner->UseAsyncRendering()) {
NPWindow* window = nullptr;
mInstanceOwner->GetWindow(window);
@@ -1244,9 +1242,12 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mInstanceOwner->NotifyPaintWaiter(aBuilder);
}
DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT);
// determine if we are printing
if (type == nsPresContext::eContext_Print) {
replacedContent.AppendNewToTop(new (aBuilder)
aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayGeneric(aBuilder, this, PaintPrintPlugin, "PrintPlugin",
nsDisplayItem::TYPE_PRINT_PLUGIN));
} else {
@@ -1260,7 +1261,7 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (aBuilder->IsPaintingToWindow() &&
state == LAYER_ACTIVE &&
IsTransparentMode()) {
replacedContent.AppendNewToTop(new (aBuilder)
aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayPluginReadback(aBuilder, this));
}
#endif
@@ -1273,17 +1274,15 @@ nsObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mInstanceOwner->GetVideos(videos);
for (uint32_t i = 0; i < videos.Length(); i++) {
replacedContent.AppendNewToTop(new (aBuilder)
aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayPluginVideo(aBuilder, this, videos[i]));
}
}
#endif
replacedContent.AppendNewToTop(new (aBuilder)
aLists.Content()->AppendNewToTop(new (aBuilder)
nsDisplayPlugin(aBuilder, this));
}
WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
}
#ifdef XP_OS2

View File

@@ -31,6 +31,8 @@ extern PRLogModuleInfo *GetLayoutPrintingLog();
#define PR_PL(_p1)
#endif
using namespace mozilla;
nsIFrame*
NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
@@ -397,19 +399,15 @@ nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext,
/**
* Remove all leaf display items that are not for descendants of
* aBuilder->GetReferenceFrame() from aList, and move all nsDisplayClip
* wrappers to their correct locations.
* aBuilder->GetReferenceFrame() from aList.
* @param aPage the page we're constructing the display list for
* @param aExtraPage the page we constructed aList for
* @param aY the Y-coordinate where aPage would be positioned relative
* to the main page (aBuilder->GetReferenceFrame()), considering only
* the content and ignoring page margins and dead space
* @param aList the list that is modified in-place
*/
static void
PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
nsPageFrame* aPage, nsIFrame* aExtraPage,
nscoord aY, nsDisplayList* aList)
nsDisplayList* aList)
{
nsDisplayList newList;
@@ -419,46 +417,26 @@ PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
break;
nsDisplayList* subList = i->GetSameCoordinateSystemChildren();
if (subList) {
PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, aY, subList);
nsDisplayItem::Type type = i->GetType();
if (type == nsDisplayItem::TYPE_CLIP ||
type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) {
// This might clip an element which should appear on the first
// page, and that element might be visible if this uses a 'clip'
// property with a negative top.
// The clip area needs to be moved because the frame geometry doesn't
// put page content frames for adjacent pages vertically adjacent,
// there are page margins and dead space between them in print
// preview, and in printing all pages are at (0,0)...
// XXX we have no way to test this right now that I know of;
// the 'clip' property requires an abs-pos element and we never
// paint abs-pos elements that start after the main page
// (bug 426909).
nsDisplayClip* clip = static_cast<nsDisplayClip*>(i);
clip->SetClipRect(clip->GetClipRect() + nsPoint(0, aY) -
aExtraPage->GetOffsetToCrossDoc(aBuilder->FindReferenceFrameFor(aPage)));
}
newList.AppendToTop(i);
PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, subList);
i->UpdateBounds(aBuilder);
} else {
nsIFrame* f = i->GetUnderlyingFrame();
if (f && nsLayoutUtils::IsProperAncestorFrameCrossDoc(aPage, f)) {
// This one is in the page we care about, keep it
newList.AppendToTop(i);
} else {
if (!f || !nsLayoutUtils::IsProperAncestorFrameCrossDoc(aPage, f)) {
// We're throwing this away so call its destructor now. The memory
// is owned by aBuilder which destroys all items at once.
i->~nsDisplayItem();
continue;
}
}
newList.AppendToTop(i);
}
aList->AppendToTop(&newList);
}
static nsresult
BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
nsPageFrame* aPage, nsIFrame* aExtraPage,
nscoord aY, nsDisplayList* aList)
nsDisplayList* aList)
{
nsDisplayList list;
// Pass an empty dirty rect since we're only interested in finding
@@ -468,7 +446,7 @@ BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder,
// 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, aY, &list);
PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, &list);
aList->AppendToTop(&list);
return NS_OK;
}
@@ -516,33 +494,7 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
DisplayBorderBackgroundOutline(aBuilder, aLists);
}
nsDisplayList content;
nsIFrame *child = mFrames.FirstChild();
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
// out-of-flow frames can't be placed after their placeholders so
// we don't have to process earlier pages. The display lists for
// these extra pages are pruned so that only display items for the
// page we currently care about (which we would have reached by
// following placeholders to their out-of-flows) end up on the list.
nsIFrame* page = child;
nscoord y = child->GetSize().height;
while ((page = GetNextPage(page)) != nullptr) {
BuildDisplayListForExtraPage(aBuilder, this, page, y, &content);
y += page->GetSize().height;
}
// 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.
nsRect backgroundRect =
nsRect(aBuilder->ToReferenceFrame(child), child->GetSize());
PresContext()->GetPresShell()->AddCanvasBackgroundColorItem(
*aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0));
float scale = PresContext()->GetPageScale();
nsRect clipRect(nsPoint(0, 0), child->GetSize());
// Note: this computation matches how we compute maxSize.height
@@ -563,7 +515,41 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
"Should be clipping to region inside the page content bounds");
}
clipRect += aBuilder->ToReferenceFrame(child);
content.AppendNewToTop(new (aBuilder) nsDisplayClip(aBuilder, child, &content, clipRect));
nsDisplayList content;
{
DisplayListClipState::AutoSaveRestore saveClip(aBuilder->ClipState());
DisplayItemClip clipOnStack;
// Overwrite current clip, since we're going to wrap in a transform
// and the current clip is no longer meaningful.
aBuilder->ClipState().Clear();
aBuilder->ClipState().ClipContainingBlockDescendants(clipRect, nullptr, clipOnStack);
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
// out-of-flow frames can't be placed after their placeholders so
// we don't have to process earlier pages. The display lists for
// these extra pages are pruned so that only display items for the
// page we currently care about (which we would have reached by
// following placeholders to their out-of-flows) end up on the list.
nsIFrame* page = child;
while ((page = GetNextPage(page)) != nullptr) {
BuildDisplayListForExtraPage(aBuilder, this, page, &content);
}
// 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.
nsRect backgroundRect =
nsRect(aBuilder->ToReferenceFrame(child), child->GetSize());
PresContext()->GetPresShell()->AddCanvasBackgroundColorItem(
*aBuilder, content, child, backgroundRect, NS_RGBA(0,0,0,0));
}
content.AppendNewToTop(new (aBuilder) nsDisplayTransform(aBuilder, child, &content, ::ComputePageTransform));
set.Content()->AppendToTop(&content);

View File

@@ -363,8 +363,6 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsPresContext* presContext = presShell->GetPresContext();
nsDisplayList childItems;
int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
@@ -385,8 +383,29 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aBuilder->EnterPresShell(subdocRootFrame, dirty);
}
nsRect subdocBoundsInParentUnits =
mInnerView->GetBounds() + aBuilder->ToReferenceFrame(this);
DisplayListClipState::AutoSaveRestore saveClip(aBuilder->ClipState());
DisplayItemClip clipOnStack;
if (ShouldClipSubdocument()) {
aBuilder->ClipState().ClipContainingBlockDescendantsToContentBox(aBuilder, this,
clipOnStack);
}
nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
bool needsOwnLayer = constructZoomItem ||
presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive());
nsDisplayList childItems;
{
DisplayListClipState::AutoSaveRestore willClearClip(aBuilder->ClipState());
if (needsOwnLayer) {
// Clear current clip. There's no point in propagating it down, since
// the layer we will construct will be clipped by the current clip.
// In fact for nsDisplayZoom propagating it down would be incorrect since
// nsDisplayZoom changes the meaning of appunits.
aBuilder->ClipState().Clear();
}
if (subdocRootFrame) {
subdocRootFrame->
@@ -399,6 +418,7 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// calculate the bounds based on which frame will be the underlying frame
// for the canvas background color item.
nsRect bounds;
nsRect subdocBoundsInParentUnits = GetContentRectRelativeToSelf();
if (subdocRootFrame) {
bounds = subdocBoundsInParentUnits.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
} else {
@@ -422,26 +442,15 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
bounds, NS_RGBA(0,0,0,0), flags);
}
}
}
bool addedLayer = false;
if (subdocRootFrame && parentAPD != subdocAPD) {
NS_WARN_IF_FALSE(!addedLayer,
"Two container layers have been added. "
"Performance may suffer.");
addedLayer = true;
if (constructZoomItem) {
nsDisplayZoom* zoomItem =
new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
subdocAPD, parentAPD,
nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS);
childItems.AppendToTop(zoomItem);
}
nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
if (!addedLayer &&
(presContext->IsRootContentDocument() ||
(sf && sf->IsScrollingActive()))) {
} else if (needsOwnLayer) {
// We always want top level content documents to be in their own layer.
nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer(
aBuilder, subdocRootFrame ? subdocRootFrame : this,
@@ -453,29 +462,15 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aBuilder->LeavePresShell(subdocRootFrame, dirty);
}
if (ShouldClipSubdocument()) {
nsDisplayClip* item =
new (aBuilder) nsDisplayClip(aBuilder, this, &childItems,
subdocBoundsInParentUnits);
// Clip children to the child root frame's rectangle
childItems.AppendToTop(item);
}
if (aBuilder->IsForImageVisibility()) {
// We don't add the childItems to the return list as we're dealing with them here.
presShell->RebuildImageVisibility(childItems);
} else {
if (mIsInline) {
WrapReplacedContentForBorderRadius(aBuilder, &childItems, aLists);
childItems.DeleteAll();
} else {
aLists.Content()->AppendToTop(&childItems);
}
}
// delete childItems in case of OOM
childItems.DeleteAll();
}
nscoord
nsSubDocumentFrame::GetIntrinsicWidth()
{

View File

@@ -417,10 +417,11 @@ nsVideoFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
DisplayBorderBackgroundOutline(aBuilder, aLists);
nsDisplayList replacedContent;
DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT);
if (HasVideoElement() && !ShouldDisplayPoster()) {
replacedContent.AppendNewToTop(
aLists.Content()->AppendNewToTop(
new (aBuilder) nsDisplayVideo(aBuilder, this));
}
@@ -433,15 +434,13 @@ nsVideoFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
if (child->GetContent() != mPosterImage || ShouldDisplayPoster()) {
child->BuildDisplayListForStackingContext(aBuilder,
aDirtyRect - child->GetOffsetTo(this),
&replacedContent);
aLists.Content());
} else if (child->GetType() == nsGkAtoms::boxFrame) {
child->BuildDisplayListForStackingContext(aBuilder,
aDirtyRect - child->GetOffsetTo(this),
&replacedContent);
aLists.Content());
}
}
WrapReplacedContentForBorderRadius(aBuilder, &replacedContent, aLists);
}
nsIAtom*

View File

@@ -948,25 +948,23 @@ RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder,
{
// We're the subdoc for <browser remote="true"> and it has
// painted content. Display its shadow layer tree.
nsDisplayList shadowTree;
DisplayListClipState::AutoSaveRestore saveClip(aBuilder->ClipState());
nsPoint offset = aBuilder->ToReferenceFrame(aFrame);
nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset;
DisplayItemClip clipOnStack;
aBuilder->ClipState().ClipContentDescendants(bounds, clipOnStack);
ContainerLayer* container = GetRootLayer();
if (aBuilder->IsForEventDelivery() && container) {
ViewTransform offset =
ViewTransform(GetContentRectLayerOffset(aFrame, aBuilder), 1, 1);
BuildListForLayer(container, mFrameLoader, offset,
aBuilder, shadowTree, aFrame);
aBuilder, *aLists.Content(), aFrame);
} else {
shadowTree.AppendToTop(
aLists.Content()->AppendToTop(
new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this));
}
// Clip the shadow layers to subdoc bounds
nsPoint offset = aBuilder->ToReferenceFrame(aFrame);
nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset;
aLists.Content()->AppendNewToTop(
new (aBuilder) nsDisplayClip(aBuilder, aFrame, &shadowTree,
bounds));
}
void

View File

@@ -53,7 +53,7 @@ fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1
fuzzy-if(cocoaWidget,1,4) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html
== intersecting-clipping-1-image.html intersecting-clipping-1-refi.html
== intersecting-clipping-1-overflow-hidden.html intersecting-clipping-1-ref.html
fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,20) fuzzy-if(Android,5,105) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
fuzzy-if(Android,5,105) fuzzy-if(d2d,1,20) == intersecting-clipping-1-refi.html intersecting-clipping-1-ref.html
fuzzy-if(true,1,33) fuzzy-if(cocoaWidget,1,332) fuzzy-if(Android&&browserIsRemote,7,310) fuzzy-if(Android&&!browserIsRemote,124,440) == intersecting-clipping-1-refc.html intersecting-clipping-1-ref.html # bug 732535
# Inheritance

View File

@@ -22,6 +22,7 @@
#include "mozilla/dom/SVGViewElement.h"
#include "nsSubDocumentFrame.h"
using namespace mozilla;
using namespace mozilla::dom;
class nsSVGMutationObserver : public nsStubMutationObserver
@@ -696,28 +697,19 @@ nsSVGOuterSVGFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
DisplayBorderBackgroundOutline(aBuilder, aLists);
nsDisplayList childItems;
DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox clip(aBuilder, this);
if ((aBuilder->IsForEventDelivery() &&
NS_SVGDisplayListHitTestingEnabled()) ||
NS_SVGDisplayListPaintingEnabled()) {
nsDisplayList *nonContentList = &childItems;
nsDisplayListSet set(nonContentList, nonContentList, nonContentList,
&childItems, nonContentList, nonContentList);
nsDisplayList *contentList = aLists.Content();
nsDisplayListSet set(contentList, contentList, contentList,
contentList, contentList, contentList);
BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, set);
} else {
childItems.AppendNewToTop(
aLists.Content()->AppendNewToTop(
new (aBuilder) nsDisplayOuterSVG(aBuilder, this));
}
// Clip to our _content_ box:
nsRect clipRect =
GetContentRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
nsDisplayClip* item =
new (aBuilder) nsDisplayClip(aBuilder, this, &childItems, clipRect);
childItems.AppendNewToTop(item);
WrapReplacedContentForBorderRadius(aBuilder, &childItems, aLists);
}
nsSplittableType