Bug 1319626 - Part 5: Minimize visible region for border layers. r?mstange
MozReview-Commit-ID: I2YWnKz13Gp
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -296,17 +296,17 @@ public:
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
{
*aSnap = true;
nsStyleBorder styleBorder = *mFrame->StyleBorder();
nsMathMLmtdFrame* frame = static_cast<nsMathMLmtdFrame*>(mFrame);
ApplyBorderToStyle(frame, styleBorder);
- nsRect bounds = CalculateBounds(styleBorder);
+ nsRect bounds = CalculateBounds(styleBorder).GetBounds();
nsMargin overflow = ComputeBorderOverflow(frame, styleBorder);
bounds.Inflate(overflow);
return bounds;
}
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override
{
nsStyleBorder styleBorder = *mFrame->StyleBorder();
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -1112,16 +1112,24 @@ public:
nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap = false) const
{
if (aSnap && mSnappingEnabled) {
return ScaleToNearestPixels(aRect);
}
return aRect.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
mAppUnitsPerDevPixel);
}
+ nsIntRegion ScaleToOutsidePixels(const nsRegion& aRegion, bool aSnap = false) const
+ {
+ if (aSnap && mSnappingEnabled) {
+ return ScaleRegionToNearestPixels(aRegion);
+ }
+ return aRegion.ScaleToOutsidePixels(mParameters.mXScale, mParameters.mYScale,
+ mAppUnitsPerDevPixel);
+ }
nsIntRect ScaleToInsidePixels(const nsRect& aRect, bool aSnap = false) const
{
if (aSnap && mSnappingEnabled) {
return ScaleToNearestPixels(aRect);
}
return aRect.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
mAppUnitsPerDevPixel);
}
@@ -4328,16 +4336,24 @@ ContainerState::ProcessDisplayItems(nsDi
SetupMaskLayer(ownLayer, layerClip);
}
}
} else if (item->GetType() == nsDisplayItem::TYPE_MASK) {
nsDisplayMask* maskItem = static_cast<nsDisplayMask*>(item);
SetupMaskLayerForCSSMask(ownLayer, maskItem);
}
+ // Convert the visible rect to a region and give the item
+ // a chance to try restrict it further.
+ nsIntRegion itemVisibleRegion = itemVisibleRect;
+ nsRegion tightBounds = item->GetTightBounds(mBuilder, &snap);
+ if (!tightBounds.IsEmpty()) {
+ itemVisibleRegion.AndWith(ScaleToOutsidePixels(tightBounds, snap));
+ }
+
ContainerLayer* oldContainer = ownLayer->GetParent();
if (oldContainer && oldContainer != mContainerLayer) {
oldContainer->RemoveChild(ownLayer);
}
NS_ASSERTION(FindIndexOfLayerIn(mNewChildLayers, ownLayer) < 0,
"Layer already in list???");
NewLayerEntry* newLayerEntry = mNewChildLayers.AppendElement();
@@ -4366,30 +4382,30 @@ ContainerState::ProcessDisplayItems(nsDi
item->Frame()->Combines3DTransformWithAncestors() ||
item->Frame()->HasPerspective()))) {
// Give untransformed visible region as outer visible region
// to avoid failure caused by singular transforms.
newLayerEntry->mUntransformedVisibleRegion = true;
newLayerEntry->mVisibleRegion =
item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel);
} else {
- newLayerEntry->mVisibleRegion = itemVisibleRect;
+ newLayerEntry->mVisibleRegion = itemVisibleRegion;
}
newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item,
animatedGeometryRoot, layerClip, aList,
&newLayerEntry->mHideAllLayersBelow,
&newLayerEntry->mOpaqueForAnimatedGeometryRootParent);
} else {
bool useChildrenVisible =
itemType == nsDisplayItem::TYPE_TRANSFORM &&
(item->Frame()->IsPreserve3DLeaf() ||
item->Frame()->HasPerspective());
const nsIntRegion &visible = useChildrenVisible ?
item->GetVisibleRectForChildren().ToOutsidePixels(mAppUnitsPerDevPixel):
- itemVisibleRect;
+ itemVisibleRegion;
SetOuterVisibleRegionForLayer(ownLayer, visible,
layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr,
useChildrenVisible);
}
if (itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) {
nsDisplayScrollInfoLayer* scrollItem = static_cast<nsDisplayScrollInfoLayer*>(item);
newLayerEntry->mOpaqueForAnimatedGeometryRootParent = false;
@@ -4680,16 +4696,23 @@ FrameLayerBuilder::AddPaintedDisplayItem
tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
return;
}
bool snap;
nsRect visibleRect =
aItem->GetVisibleRect().Intersect(aItem->GetBounds(mDisplayListBuilder, &snap));
nsIntRegion rgn = visibleRect.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel);
+
+ // Convert the visible rect to a region and give the item
+ // a chance to try restrict it further.
+ nsRegion tightBounds = aItem->GetTightBounds(mDisplayListBuilder, &snap);
+ if (!tightBounds.IsEmpty()) {
+ rgn.AndWith(tightBounds.ToOutsidePixels(paintedData->mAppUnitsPerDevPixel));
+ }
SetOuterVisibleRegion(tmpLayer, &rgn);
// If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been
// stored in layerBuilder. Manually add it now.
if (mRetainingManager) {
#ifdef DEBUG_DISPLAY_ITEM_DATA
LayerManagerData* parentLmd = static_cast<LayerManagerData*>
(layer->Manager()->GetUserData(&gLayerManagerUserData));
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4001,17 +4001,17 @@ nsDisplayCaret::Paint(nsDisplayListBuild
mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
}
nsDisplayBorder::nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
: nsDisplayItem(aBuilder, aFrame)
{
MOZ_COUNT_CTOR(nsDisplayBorder);
- mBounds = CalculateBounds(*mFrame->StyleBorder());
+ mBounds = CalculateBounds(*mFrame->StyleBorder()).GetBounds();
}
bool
nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect)
{
nsRect paddingRect = mFrame->GetPaddingRect() - mFrame->GetPosition() +
ToReferenceFrame();
const nsStyleBorder *styleBorder;
@@ -4154,56 +4154,56 @@ nsDisplayBorder::Paint(nsDisplayListBuil
nsRect
nsDisplayBorder::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
{
*aSnap = true;
return mBounds;
}
-nsRect
+nsRegion
nsDisplayBorder::CalculateBounds(const nsStyleBorder& aStyleBorder)
{
nsRect borderBounds(ToReferenceFrame(), mFrame->GetSize());
if (aStyleBorder.IsBorderImageLoaded()) {
borderBounds.Inflate(aStyleBorder.GetImageOutset());
return borderBounds;
} else {
nsMargin border = aStyleBorder.GetComputedBorder();
- nsRect result;
+ nsRegion result;
if (border.top > 0) {
result = nsRect(borderBounds.X(), borderBounds.Y(), borderBounds.Width(), border.top);
}
if (border.right > 0) {
- result.UnionRect(result, nsRect(borderBounds.XMost() - border.right, borderBounds.Y(), border.right, borderBounds.Height()));
+ result.OrWith(nsRect(borderBounds.XMost() - border.right, borderBounds.Y(), border.right, borderBounds.Height()));
}
if (border.bottom > 0) {
- result.UnionRect(result, nsRect(borderBounds.X(), borderBounds.YMost() - border.bottom, borderBounds.Width(), border.bottom));
+ result.OrWith(nsRect(borderBounds.X(), borderBounds.YMost() - border.bottom, borderBounds.Width(), border.bottom));
}
if (border.left > 0) {
- result.UnionRect(result, nsRect(borderBounds.X(), borderBounds.Y(), border.left, borderBounds.Height()));
+ result.OrWith(nsRect(borderBounds.X(), borderBounds.Y(), border.left, borderBounds.Height()));
}
nscoord radii[8];
if (mFrame->GetBorderRadii(radii)) {
if (border.left > 0 || border.top > 0) {
nsSize cornerSize(radii[NS_CORNER_TOP_LEFT_X], radii[NS_CORNER_TOP_LEFT_Y]);
- result.UnionRect(result, nsRect(borderBounds.TopLeft(), cornerSize));
+ result.OrWith(nsRect(borderBounds.TopLeft(), cornerSize));
}
if (border.top > 0 || border.right > 0) {
nsSize cornerSize(radii[NS_CORNER_TOP_RIGHT_X], radii[NS_CORNER_TOP_RIGHT_Y]);
- result.UnionRect(result, nsRect(borderBounds.TopRight() - nsPoint(cornerSize.width, 0), cornerSize));
+ result.OrWith(nsRect(borderBounds.TopRight() - nsPoint(cornerSize.width, 0), cornerSize));
}
if (border.right > 0 || border.bottom > 0) {
nsSize cornerSize(radii[NS_CORNER_BOTTOM_RIGHT_X], radii[NS_CORNER_BOTTOM_RIGHT_Y]);
- result.UnionRect(result, nsRect(borderBounds.BottomRight() - nsPoint(cornerSize.width, cornerSize.height), cornerSize));
+ result.OrWith(nsRect(borderBounds.BottomRight() - nsPoint(cornerSize.width, cornerSize.height), cornerSize));
}
if (border.bottom > 0 || border.left > 0) {
nsSize cornerSize(radii[NS_CORNER_BOTTOM_LEFT_X], radii[NS_CORNER_BOTTOM_LEFT_Y]);
- result.UnionRect(result, nsRect(borderBounds.BottomLeft() - nsPoint(0, cornerSize.height), cornerSize));
+ result.OrWith(nsRect(borderBounds.BottomLeft() - nsPoint(0, cornerSize.height), cornerSize));
}
}
return result;
}
}
// Given a region, compute a conservative approximation to it as a list
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1422,16 +1422,23 @@ public:
* @return a rectangle relative to aBuilder->ReferenceFrame() that
* contains the area drawn by this display item
*/
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
{
*aSnap = false;
return nsRect(ToReferenceFrame(), Frame()->GetSize());
}
+
+ virtual nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
+ {
+ *aSnap = false;
+ return nsRegion();
+ }
+
/**
* Returns true if nothing will be rendered inside aRect, false if uncertain.
* aRect is assumed to be contained in this item's bounds.
*/
virtual bool IsInvisibleInRect(const nsRect& aRect)
{
return false;
}
@@ -2569,18 +2576,24 @@ public:
NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override;
+ virtual nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
+ {
+ *aSnap = true;
+ return CalculateBounds(*mFrame->StyleBorder());
+ }
+
protected:
- nsRect CalculateBounds(const nsStyleBorder& aStyleBorder);
+ nsRegion CalculateBounds(const nsStyleBorder& aStyleBorder);
mozilla::Array<mozilla::gfx::Color, 4> mColors;
mozilla::Array<mozilla::LayerCoord, 4> mWidths;
mozilla::LayerRect mRect;
nsRect mBounds;
};