Bug 602757. Part 3: Change IsOpaque to GetOpaqueRegion so we can get useful opaque regions for content that uses border-radius. r=tnikkel,sr=dbaron,a=blocking

This commit is contained in:
Robert O'Callahan 2011-01-03 14:48:09 +13:00
Родитель 360d34a263
Коммит e7ff7b3a5f
14 изменённых файлов: 209 добавлений и 121 удалений

Просмотреть файл

@ -1486,8 +1486,10 @@ namespace {
nsRect nsRegion::GetLargestRectangle () const { nsRect nsRegion::GetLargestRectangle () const {
nsRect bestRect; nsRect bestRect;
if (!mRectCount) if (mRectCount <= 1) {
bestRect = mBoundRect;
return bestRect; return bestRect;
}
AxisPartition xaxis, yaxis; AxisPartition xaxis, yaxis;

Просмотреть файл

@ -186,7 +186,8 @@ protected:
void Accumulate(nsDisplayListBuilder* aBuilder, void Accumulate(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem, nsDisplayItem* aItem,
const nsIntRect& aVisibleRect, const nsIntRect& aVisibleRect,
const nsIntRect& aDrawRect); const nsIntRect& aDrawRect,
const FrameLayerBuilder::Clip& aClip);
nsIFrame* GetActiveScrolledRoot() { return mActiveScrolledRoot; } nsIFrame* GetActiveScrolledRoot() { return mActiveScrolledRoot; }
/** /**
@ -307,6 +308,7 @@ protected:
already_AddRefed<ThebesLayer> FindThebesLayerFor(nsDisplayItem* aItem, already_AddRefed<ThebesLayer> FindThebesLayerFor(nsDisplayItem* aItem,
const nsIntRect& aVisibleRect, const nsIntRect& aVisibleRect,
const nsIntRect& aDrawRect, const nsIntRect& aDrawRect,
const FrameLayerBuilder::Clip& aClip,
nsIFrame* aActiveScrolledRoot); nsIFrame* aActiveScrolledRoot);
ThebesLayerData* GetTopThebesLayerData() ThebesLayerData* GetTopThebesLayerData()
{ {
@ -922,7 +924,8 @@ void
ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder, ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem, nsDisplayItem* aItem,
const nsIntRect& aVisibleRect, const nsIntRect& aVisibleRect,
const nsIntRect& aDrawRect) const nsIntRect& aDrawRect,
const FrameLayerBuilder::Clip& aClip)
{ {
nscolor uniformColor; nscolor uniformColor;
if (aItem->IsUniform(aBuilder, &uniformColor)) { if (aItem->IsUniform(aBuilder, &uniformColor)) {
@ -947,18 +950,25 @@ ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder,
mDrawRegion.SimplifyOutward(4); mDrawRegion.SimplifyOutward(4);
PRBool forceTransparentSurface = PR_FALSE; PRBool forceTransparentSurface = PR_FALSE;
if (aItem->IsOpaque(aBuilder, &forceTransparentSurface)) { nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, &forceTransparentSurface);
// We don't use SimplifyInward here since it's not defined exactly if (!opaque.IsEmpty()) {
// what it will discard. For our purposes the most important case nsRegionRectIterator iter(opaque);
// is a large opaque background at the bottom of z-order (e.g., nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
// a canvas background), so we need to make sure that the first rect for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
// we see doesn't get discarded. // We don't use SimplifyInward here since it's not defined exactly
nsIntRegion tmp; // what it will discard. For our purposes the most important case
tmp.Or(mOpaqueRegion, aDrawRect); // is a large opaque background at the bottom of z-order (e.g.,
if (tmp.GetNumRects() <= 4) { // a canvas background), so we need to make sure that the first rect
mOpaqueRegion = tmp; // we see doesn't get discarded.
nsIntRect rect = aClip.ApproximateIntersect(*r).ToNearestPixels(appUnitsPerDevPixel);
nsIntRegion tmp;
tmp.Or(mOpaqueRegion, rect);
if (tmp.GetNumRects() <= 4) {
mOpaqueRegion = tmp;
}
} }
} else if (aItem->HasText()) { }
if (aItem->HasText()) {
if (!mOpaqueRegion.Contains(aVisibleRect)) { if (!mOpaqueRegion.Contains(aVisibleRect)) {
if (SuppressComponentAlpha(aBuilder, aItem)) { if (SuppressComponentAlpha(aBuilder, aItem)) {
aItem->DisableComponentAlpha(); aItem->DisableComponentAlpha();
@ -974,6 +984,7 @@ already_AddRefed<ThebesLayer>
ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
const nsIntRect& aVisibleRect, const nsIntRect& aVisibleRect,
const nsIntRect& aDrawRect, const nsIntRect& aDrawRect,
const FrameLayerBuilder::Clip& aClip,
nsIFrame* aActiveScrolledRoot) nsIFrame* aActiveScrolledRoot)
{ {
PRInt32 i; PRInt32 i;
@ -1028,7 +1039,7 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem,
layer = thebesLayerData->mLayer; layer = thebesLayerData->mLayer;
} }
thebesLayerData->Accumulate(mBuilder, aItem, aVisibleRect, aDrawRect); thebesLayerData->Accumulate(mBuilder, aItem, aVisibleRect, aDrawRect, aClip);
return layer.forget(); return layer.forget();
} }
@ -1175,7 +1186,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
} }
nsRefPtr<ThebesLayer> thebesLayer = nsRefPtr<ThebesLayer> thebesLayer =
FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip,
activeScrolledRoot); activeScrolledRoot);
InvalidateForLayerChange(item, thebesLayer); InvalidateForLayerChange(item, thebesLayer);
@ -1814,4 +1825,20 @@ FrameLayerBuilder::Clip::ApplyTo(gfxContext* aContext,
} }
} }
nsRect
FrameLayerBuilder::Clip::ApproximateIntersect(const nsRect& aRect) const
{
nsRect r = aRect;
if (mHaveClipRect) {
r.IntersectRect(r, mClipRect);
}
for (PRUint32 i = 0, iEnd = mRoundedClipRects.Length();
i < iEnd; ++i) {
const Clip::RoundedRect &rr = mRoundedClipRects[i];
nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(rr.mRect, rr.mRadii, r);
r = rgn.GetLargestRectangle();
}
return r;
}
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -317,6 +317,11 @@ public:
// or clearing of other clips must be done by the caller. // or clearing of other clips must be done by the caller.
void ApplyTo(gfxContext* aContext, nsPresContext* aPresContext); void ApplyTo(gfxContext* aContext, nsPresContext* aPresContext);
// Return a rectangle contained in the intersection of aRect with this
// clip region. Tries to return the largest possible rectangle, but may
// not succeed.
nsRect ApproximateIntersect(const nsRect& aRect) const;
bool operator==(const Clip& aOther) const { bool operator==(const Clip& aOther) const {
return mHaveClipRect == aOther.mHaveClipRect && return mHaveClipRect == aOther.mHaveClipRect &&
(!mHaveClipRect || mClipRect == aOther.mClipRect) && (!mHaveClipRect || mClipRect == aOther.mClipRect) &&

Просмотреть файл

@ -174,6 +174,9 @@ void
nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion, nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
const nsRegion& aRegion) const nsRegion& aRegion)
{ {
if (aRegion.IsEmpty())
return;
nsRegion tmp; nsRegion tmp;
tmp.Sub(*aVisibleRegion, aRegion); tmp.Sub(*aVisibleRegion, aRegion);
// Don't let *aVisibleRegion get too complex, but don't let it fluff out // Don't let *aVisibleRegion get too complex, but don't let it fluff out
@ -310,19 +313,19 @@ nsDisplayList::ComputeVisibilityForRoot(nsDisplayListBuilder* aBuilder,
return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds()); return ComputeVisibilityForSublist(aBuilder, aVisibleRegion, r.GetBounds());
} }
static PRBool static nsRegion
TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder, TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder,
PRBool* aTransparentBackground) PRBool* aTransparentBackground)
{ {
if (aItem->IsOpaque(aBuilder, aTransparentBackground)) nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, aTransparentBackground);
return PR_TRUE;
if (aBuilder->IsForPluginGeometry()) { if (aBuilder->IsForPluginGeometry()) {
// Treat all chrome items as opaque // Treat all chrome items as opaque
nsIFrame* f = aItem->GetUnderlyingFrame(); nsIFrame* f = aItem->GetUnderlyingFrame();
if (f && f->PresContext()->IsChrome()) if (f && f->PresContext()->IsChrome()) {
return PR_TRUE; opaque = aItem->GetBounds(aBuilder);
}
} }
return PR_FALSE; return opaque;
} }
PRBool PRBool
@ -362,10 +365,9 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
if (item->ComputeVisibility(aBuilder, aVisibleRegion)) { if (item->ComputeVisibility(aBuilder, aVisibleRegion)) {
anyVisible = PR_TRUE; anyVisible = PR_TRUE;
PRBool transparentBackground = PR_FALSE; PRBool transparentBackground = PR_FALSE;
if (TreatAsOpaque(item, aBuilder, &transparentBackground)) { nsRegion opaque = TreatAsOpaque(item, aBuilder, &transparentBackground);
// Subtract opaque item from the visible region // Subtract opaque item from the visible region
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, nsRegion(bounds)); aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
}
forceTransparentSurface = forceTransparentSurface || transparentBackground; forceTransparentSurface = forceTransparentSurface || transparentBackground;
} }
AppendToBottom(item); AppendToBottom(item);
@ -686,9 +688,8 @@ PRBool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
return PR_FALSE; return PR_FALSE;
PRBool forceTransparentBackground; PRBool forceTransparentBackground;
if (TreatAsOpaque(this, aBuilder, &forceTransparentBackground)) { nsRegion opaque = TreatAsOpaque(this, aBuilder, &forceTransparentBackground);
aVisibleRegion->Sub(*aVisibleRegion, bounds); aVisibleRegion->Sub(*aVisibleRegion, opaque);
}
return PR_TRUE; return PR_TRUE;
} }
@ -834,25 +835,8 @@ RoundedBorderIntersectsRect(nsIFrame* aFrame,
static PRBool RoundedRectContainsRect(const nsRect& aRoundedRect, static PRBool RoundedRectContainsRect(const nsRect& aRoundedRect,
const nscoord aRadii[8], const nscoord aRadii[8],
const nsRect& aContainedRect) { const nsRect& aContainedRect) {
// rectFullHeight and rectFullWidth together will approximately contain nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect);
// the total area of the frame minus the rounded corners. return rgn.Contains(aContainedRect);
nsRect rectFullHeight = aRoundedRect;
nscoord xDiff = NS_MAX(aRadii[NS_CORNER_TOP_LEFT_X], aRadii[NS_CORNER_BOTTOM_LEFT_X]);
rectFullHeight.x += xDiff;
rectFullHeight.width -= NS_MAX(aRadii[NS_CORNER_TOP_RIGHT_X],
aRadii[NS_CORNER_BOTTOM_RIGHT_X]) + xDiff;
if (rectFullHeight.Contains(aContainedRect))
return PR_TRUE;
nsRect rectFullWidth = aRoundedRect;
nscoord yDiff = NS_MAX(aRadii[NS_CORNER_TOP_LEFT_Y], aRadii[NS_CORNER_TOP_RIGHT_Y]);
rectFullWidth.y += yDiff;
rectFullWidth.height -= NS_MAX(aRadii[NS_CORNER_BOTTOM_LEFT_Y],
aRadii[NS_CORNER_BOTTOM_RIGHT_Y]) + yDiff;
if (rectFullWidth.Contains(aContainedRect))
return PR_TRUE;
return PR_FALSE;
} }
void void
@ -888,9 +872,10 @@ nsDisplayBackground::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC); nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
} }
PRBool nsRegion
nsDisplayBackground::IsOpaque(nsDisplayListBuilder* aBuilder, nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) { PRBool* aForceTransparentSurface) {
nsRegion result;
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
@ -901,27 +886,34 @@ nsDisplayBackground::IsOpaque(nsDisplayListBuilder* aBuilder,
*aForceTransparentSurface = disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS || *aForceTransparentSurface = disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
disp->mAppearance == NS_THEME_WIN_GLASS; disp->mAppearance == NS_THEME_WIN_GLASS;
} }
return mThemeTransparency == nsITheme::eOpaque; if (mThemeTransparency == nsITheme::eOpaque) {
result = GetBounds(aBuilder);
}
return result;
} }
nsStyleContext* bgSC; nsStyleContext* bgSC;
if (!nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC)) if (!nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC))
return PR_FALSE; return result;
const nsStyleBackground* bg = bgSC->GetStyleBackground(); const nsStyleBackground* bg = bgSC->GetStyleBackground();
const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer(); const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer();
// bottom layer's clip is used for the color // bottom layer's clip is used for the color
if (bottomLayer.mClip != NS_STYLE_BG_CLIP_BORDER || if (bottomLayer.mClip != NS_STYLE_BG_CLIP_BORDER ||
nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius)) nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius))
return PR_FALSE; return result;
if (NS_GET_A(bg->mBackgroundColor) == 255 && if (NS_GET_A(bg->mBackgroundColor) == 255 &&
!nsCSSRendering::IsCanvasFrame(mFrame)) !nsCSSRendering::IsCanvasFrame(mFrame)) {
return PR_TRUE; result = GetBounds(aBuilder);
return result;
}
return bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY && if (bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY &&
bottomLayer.mImage.IsOpaque(); bottomLayer.mImage.IsOpaque()) {
result = GetBounds(aBuilder);
}
return result;
} }
PRBool PRBool
@ -1283,13 +1275,17 @@ nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
mVisibleRect); mVisibleRect);
} }
PRBool nsRegion
nsDisplayWrapList::IsOpaque(nsDisplayListBuilder* aBuilder, nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) { PRBool* aForceTransparentSurface) {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
return mList.IsOpaque(); nsRegion result;
if (mList.IsOpaque()) {
result = GetBounds(aBuilder);
}
return result;
} }
PRBool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) { PRBool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
@ -1427,14 +1423,14 @@ nsDisplayOpacity::~nsDisplayOpacity() {
} }
#endif #endif
PRBool nsDisplayOpacity::IsOpaque(nsDisplayListBuilder* aBuilder, nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) { PRBool* aForceTransparentSurface) {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
// We are never opaque, if our opacity was < 1 then we wouldn't have // We are never opaque, if our opacity was < 1 then we wouldn't have
// been created. // been created.
return PR_FALSE; return nsRegion();
} }
// nsDisplayOpacity uses layers for rendering // nsDisplayOpacity uses layers for rendering
@ -1601,13 +1597,14 @@ nsDisplayClipRoundedRect::~nsDisplayClipRoundedRect()
} }
#endif #endif
PRBool nsDisplayClipRoundedRect::IsOpaque(nsDisplayListBuilder* aBuilder, nsRegion
nsDisplayClipRoundedRect::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) PRBool* aForceTransparentSurface)
{ {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
return PR_FALSE; return nsRegion();
} }
void void
@ -2021,8 +2018,8 @@ nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder)
* mStoredList.GetVisibleRect().Contains(untransformedVisible), then it * mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
* certainly contains the actual (non-axis-aligned) untransformed rect. * certainly contains the actual (non-axis-aligned) untransformed rect.
*/ */
PRBool nsDisplayTransform::IsOpaque(nsDisplayListBuilder *aBuilder, nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
PRBool* aForceTransparentSurface) PRBool* aForceTransparentSurface)
{ {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
@ -2030,14 +2027,17 @@ PRBool nsDisplayTransform::IsOpaque(nsDisplayListBuilder *aBuilder,
const nsStyleDisplay* disp = mFrame->GetStyleDisplay(); const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
nsRect untransformedVisible = nsRect untransformedVisible =
UntransformRect(mVisibleRect, mFrame, ToReferenceFrame()); UntransformRect(mVisibleRect, mFrame, ToReferenceFrame());
return disp->mTransform.GetMainMatrixEntry(1) == 0.0f && nsRegion result;
disp->mTransform.GetMainMatrixEntry(2) == 0.0f && if (disp->mTransform.GetMainMatrixEntry(1) == 0.0f &&
mStoredList.GetVisibleRect().Contains(untransformedVisible) && disp->mTransform.GetMainMatrixEntry(2) == 0.0f &&
mStoredList.IsOpaque(aBuilder); mStoredList.GetOpaqueRegion(aBuilder).Contains(untransformedVisible)) {
result = mVisibleRect;
}
return result;
} }
/* The transform is uniform if it fills the entire bounding rect and the /* The transform is uniform if it fills the entire bounding rect and the
* wrapped list is uniform. See IsOpaque for discussion of why this * wrapped list is uniform. See GetOpaqueRegion for discussion of why this
* works. * works.
*/ */
PRBool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor) PRBool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor)
@ -2161,13 +2161,13 @@ nsDisplaySVGEffects::~nsDisplaySVGEffects()
} }
#endif #endif
PRBool nsDisplaySVGEffects::IsOpaque(nsDisplayListBuilder* aBuilder, nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) PRBool* aForceTransparentSurface)
{ {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
return PR_FALSE; return nsRegion();
} }
void void

Просмотреть файл

@ -559,16 +559,16 @@ public:
return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize()); return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
} }
/** /**
* @return PR_TRUE if the item is definitely opaque --- i.e., paints * @return a region of the item that is opaque --- every pixel painted
* every pixel within its bounds opaquely * with an opaque color.
*/ */
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull) PRBool* aForceTransparentSurface = nsnull)
{ {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
return PR_FALSE; return nsRegion();
} }
/** /**
* If this returns true, then aColor is set to the uniform color * If this returns true, then aColor is set to the uniform color
@ -641,11 +641,10 @@ public:
* On entry, aVisibleRegion contains the region (relative to ReferenceFrame()) * On entry, aVisibleRegion contains the region (relative to ReferenceFrame())
* which may be visible. If the display item opaquely covers an area, it * which may be visible. If the display item opaquely covers an area, it
* can remove that area from aVisibleRegion before returning. * can remove that area from aVisibleRegion before returning.
* nsDisplayList::ComputeVisibility automatically subtracts the bounds * nsDisplayList::ComputeVisibility automatically subtracts the region
* of items that return true from IsOpaque(), and automatically * returned by GetOpaqueRegion, and automatically removes items whose bounds
* removes items whose bounds do not intersect the visible area, * do not intersect the visible area, so implementations of
* so implementations of nsDisplayItem::ComputeVisibility do not * nsDisplayItem::ComputeVisibility do not need to do these things.
* need to do these things.
* nsDisplayList::ComputeVisibility will already have set mVisibleRect on * nsDisplayList::ComputeVisibility will already have set mVisibleRect on
* this item to the intersection of *aVisibleRegion and this item's bounds. * this item to the intersection of *aVisibleRegion and this item's bounds.
* We rely on that, so this should only be called by * We rely on that, so this should only be called by
@ -1360,12 +1359,16 @@ public:
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { return mBounds; } virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { return mBounds; }
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aOutTransparentBackground = nsnull) { PRBool* aOutTransparentBackground = nsnull) {
if (aOutTransparentBackground) { if (aOutTransparentBackground) {
*aOutTransparentBackground = PR_FALSE; *aOutTransparentBackground = PR_FALSE;
} }
return (NS_GET_A(mColor) == 255); nsRegion result;
if (NS_GET_A(mColor) == 255) {
result = GetBounds(aBuilder);
}
return result;
} }
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor)
@ -1400,8 +1403,8 @@ public:
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames); HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder, virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion); nsRegion* aVisibleRegion);
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull); PRBool* aForceTransparentSurface = nsnull);
virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame); nsIFrame* aFrame);
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor); virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor);
@ -1536,8 +1539,8 @@ public:
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames); HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder); virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull); PRBool* aForceTransparentSurface = nsnull);
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor); virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor);
virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame); nsIFrame* aFrame);
@ -1620,8 +1623,8 @@ public:
virtual ~nsDisplayOpacity(); virtual ~nsDisplayOpacity();
#endif #endif
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull); PRBool* aForceTransparentSurface = nsnull);
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager); LayerManager* aManager);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
@ -1718,8 +1721,8 @@ public:
virtual ~nsDisplayClipRoundedRect(); virtual ~nsDisplayClipRoundedRect();
#endif #endif
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull); PRBool* aForceTransparentSurface = nsnull);
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames); HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder, virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
@ -1788,8 +1791,8 @@ public:
virtual ~nsDisplaySVGEffects(); virtual ~nsDisplaySVGEffects();
#endif #endif
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull); PRBool* aForceTransparentSurface = nsnull);
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames); HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames);
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
@ -1847,8 +1850,8 @@ public:
virtual void HitTest(nsDisplayListBuilder *aBuilder, const nsRect& aRect, virtual void HitTest(nsDisplayListBuilder *aBuilder, const nsRect& aRect,
HitTestState *aState, nsTArray<nsIFrame*> *aOutFrames); HitTestState *aState, nsTArray<nsIFrame*> *aOutFrames);
virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder); virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder);
virtual PRBool IsOpaque(nsDisplayListBuilder *aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
PRBool* aForceTransparentSurface = nsnull); PRBool* aForceTransparentSurface = nsnull);
virtual PRBool IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor); virtual PRBool IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor);
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager); LayerManager* aManager);

Просмотреть файл

@ -178,11 +178,15 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
nscolor color; nscolor color;
nsRect vis = i->GetVisibleRect(); nsRect vis = i->GetVisibleRect();
nsDisplayList* list = i->GetList(); nsDisplayList* list = i->GetList();
nsRegion opaque;
if (!list || list->DidComputeVisibility()) {
opaque = i->GetOpaqueRegion(aBuilder);
}
fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)(%d,%d,%d,%d)%s%s\n", fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)(%d,%d,%d,%d)%s%s\n",
i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(), i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
rect.x, rect.y, rect.width, rect.height, rect.x, rect.y, rect.width, rect.height,
vis.x, vis.y, vis.width, vis.height, vis.x, vis.y, vis.width, vis.height,
((!list || list->DidComputeVisibility()) && i->IsOpaque(aBuilder)) ? " opaque" : "", opaque.IsEmpty() ? "" : " opaque",
i->IsUniform(aBuilder, &color) ? " uniform" : ""); i->IsUniform(aBuilder, &color) ? " uniform" : "");
if (list) { if (list) {
PrintDisplayListTo(aBuilder, *list, aIndent + 4, aOutput); PrintDisplayListTo(aBuilder, *list, aIndent + 4, aOutput);

Просмотреть файл

@ -923,6 +923,35 @@ nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
nscoord(scaledRect.size.width), nscoord(scaledRect.size.height)); nscoord(scaledRect.size.width), nscoord(scaledRect.size.height));
} }
nsRegion
nsLayoutUtils::RoundedRectIntersectRect(const nsRect& aRoundedRect,
const nscoord aRadii[8],
const nsRect& aContainedRect)
{
// rectFullHeight and rectFullWidth together will approximately contain
// the total area of the frame minus the rounded corners.
nsRect rectFullHeight = aRoundedRect;
nscoord xDiff = NS_MAX(aRadii[NS_CORNER_TOP_LEFT_X], aRadii[NS_CORNER_BOTTOM_LEFT_X]);
rectFullHeight.x += xDiff;
rectFullHeight.width -= NS_MAX(aRadii[NS_CORNER_TOP_RIGHT_X],
aRadii[NS_CORNER_BOTTOM_RIGHT_X]) + xDiff;
nsRect r1;
r1.IntersectRect(rectFullHeight, aContainedRect);
nsRect rectFullWidth = aRoundedRect;
nscoord yDiff = NS_MAX(aRadii[NS_CORNER_TOP_LEFT_Y], aRadii[NS_CORNER_TOP_RIGHT_Y]);
rectFullWidth.y += yDiff;
rectFullWidth.height -= NS_MAX(aRadii[NS_CORNER_BOTTOM_LEFT_Y],
aRadii[NS_CORNER_BOTTOM_RIGHT_Y]) + yDiff;
nsRect r2;
r2.IntersectRect(rectFullWidth, aContainedRect);
nsRegion result;
result.Or(r1, r2);
return result;
}
nsRect nsRect
nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds, nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
const gfxMatrix &aMatrix, float aFactor) const gfxMatrix &aMatrix, float aFactor)

Просмотреть файл

@ -512,6 +512,15 @@ public:
*/ */
static nsRect RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor); static nsRect RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor);
/**
* Returns a subrectangle of aContainedRect that is entirely inside the rounded
* rect. Complex cases are handled conservatively by returning a smaller
* rect than necessary.
*/
static nsRegion RoundedRectIntersectRect(const nsRect& aRoundedRect,
const nscoord aRadii[8],
const nsRect& aContainedRect);
enum { enum {
PAINT_IN_TRANSFORM = 0x01, PAINT_IN_TRANSFORM = 0x01,
PAINT_SYNC_DECODE_IMAGES = 0x02, PAINT_SYNC_DECODE_IMAGES = 0x02,

Просмотреть файл

@ -177,14 +177,15 @@ public:
return NS_GET_A(mExtraBackgroundColor) > 0 || return NS_GET_A(mExtraBackgroundColor) > 0 ||
nsDisplayBackground::ComputeVisibility(aBuilder, aVisibleRegion); nsDisplayBackground::ComputeVisibility(aBuilder, aVisibleRegion);
} }
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull) PRBool* aForceTransparentSurface = nsnull)
{ {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
return NS_GET_A(mExtraBackgroundColor) == 255 || if (NS_GET_A(mExtraBackgroundColor) == 255)
nsDisplayBackground::IsOpaque(aBuilder); return nsRegion(GetBounds(aBuilder));
return nsDisplayBackground::GetOpaqueRegion(aBuilder);
} }
virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) virtual PRBool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor)
{ {

Просмотреть файл

@ -77,14 +77,18 @@ public:
NS_DISPLAY_DECL_NAME("nsDisplayCanvas", TYPE_CANVAS) NS_DISPLAY_DECL_NAME("nsDisplayCanvas", TYPE_CANVAS)
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull) { PRBool* aForceTransparentSurface = nsnull) {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
nsIFrame* f = GetUnderlyingFrame(); nsIFrame* f = GetUnderlyingFrame();
nsHTMLCanvasElement *canvas = CanvasElementFromContent(f->GetContent()); nsHTMLCanvasElement *canvas = CanvasElementFromContent(f->GetContent());
return canvas->GetIsOpaque(); nsRegion result;
if (canvas->GetIsOpaque()) {
result = GetBounds(aBuilder);
}
return result;
} }
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {

Просмотреть файл

@ -1290,13 +1290,14 @@ nsDisplayPlugin::ComputeVisibility(nsDisplayListBuilder* aBuilder,
return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion); return nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion);
} }
PRBool nsRegion
nsDisplayPlugin::IsOpaque(nsDisplayListBuilder* aBuilder, nsDisplayPlugin::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) PRBool* aForceTransparentSurface)
{ {
if (aForceTransparentSurface) { if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE; *aForceTransparentSurface = PR_FALSE;
} }
nsRegion result;
nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame); nsObjectFrame* f = static_cast<nsObjectFrame*>(mFrame);
if (!aBuilder->IsForPluginGeometry()) { if (!aBuilder->IsForPluginGeometry()) {
nsIWidget* widget = f->GetWidget(); nsIWidget* widget = f->GetWidget();
@ -1310,11 +1311,14 @@ nsDisplayPlugin::IsOpaque(nsDisplayListBuilder* aBuilder,
// Something has clipped us unexpectedly. Perhaps there is a translucent // Something has clipped us unexpectedly. Perhaps there is a translucent
// chrome element overlaying us that forced us to be clipped away. Treat // chrome element overlaying us that forced us to be clipped away. Treat
// us as non-opaque since we may have holes. // us as non-opaque since we may have holes.
return PR_FALSE; return result;
} }
} }
} }
return f->IsOpaque(); if (f->IsOpaque()) {
result = GetBounds(aBuilder);
}
return result;
} }
void void

Просмотреть файл

@ -316,8 +316,8 @@ public:
#endif #endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder); virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
virtual PRBool IsOpaque(nsDisplayListBuilder* aBuilder, virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface = nsnull); PRBool* aForceTransparentSurface = nsnull);
virtual void Paint(nsDisplayListBuilder* aBuilder, virtual void Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx); nsIRenderingContext* aCtx);
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder, virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,

Просмотреть файл

@ -375,10 +375,10 @@ public:
NS_DISPLAY_DECL_NAME("Video", TYPE_VIDEO) NS_DISPLAY_DECL_NAME("Video", TYPE_VIDEO)
// It would be great if we could override IsOpaque to return false here, // It would be great if we could override GetOpaqueRegion to return nonempty here,
// but it's probably not safe to do so in general. Video frames are // but it's probably not safe to do so in general. Video frames are
// updated asynchronously from decoder threads, and it's possible that // updated asynchronously from decoder threads, and it's possible that
// we might have an opaque video frame when IsOpaque is called, but // we might have an opaque video frame when GetOpaqueRegion is called, but
// when we come to paint, the video frame is transparent or has gone // when we come to paint, the video frame is transparent or has gone
// away completely (e.g. because of a decoder error). The problem would // away completely (e.g. because of a decoder error). The problem would
// be especially acute if we have off-main-thread rendering. // be especially acute if we have off-main-thread rendering.

Просмотреть файл

@ -280,7 +280,7 @@ struct nsStyleImage {
// rect is non-trivial since each side value can be specified with // rect is non-trivial since each side value can be specified with
// percentage unit, which can not be evaluated until the source image size // percentage unit, which can not be evaluated until the source image size
// is available. Therefore, we currently postpone the evaluation of crop // is available. Therefore, we currently postpone the evaluation of crop
// rect until the actual rendering time --- alternatively until IsOpaque() // rect until the actual rendering time --- alternatively until GetOpaqueRegion()
// is called. // is called.
return mType == eStyleImageType_Null; return mType == eStyleImageType_Null;
} }