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 bestRect;
if (!mRectCount)
if (mRectCount <= 1) {
bestRect = mBoundRect;
return bestRect;
}
AxisPartition xaxis, yaxis;

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

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

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

@ -317,6 +317,11 @@ public:
// or clearing of other clips must be done by the caller.
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 {
return mHaveClipRect == aOther.mHaveClipRect &&
(!mHaveClipRect || mClipRect == aOther.mClipRect) &&

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

@ -174,6 +174,9 @@ void
nsDisplayListBuilder::SubtractFromVisibleRegion(nsRegion* aVisibleRegion,
const nsRegion& aRegion)
{
if (aRegion.IsEmpty())
return;
nsRegion tmp;
tmp.Sub(*aVisibleRegion, aRegion);
// 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());
}
static PRBool
static nsRegion
TreatAsOpaque(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder,
PRBool* aTransparentBackground)
{
if (aItem->IsOpaque(aBuilder, aTransparentBackground))
return PR_TRUE;
nsRegion opaque = aItem->GetOpaqueRegion(aBuilder, aTransparentBackground);
if (aBuilder->IsForPluginGeometry()) {
// Treat all chrome items as opaque
nsIFrame* f = aItem->GetUnderlyingFrame();
if (f && f->PresContext()->IsChrome())
return PR_TRUE;
if (f && f->PresContext()->IsChrome()) {
opaque = aItem->GetBounds(aBuilder);
}
}
return PR_FALSE;
return opaque;
}
PRBool
@ -362,10 +365,9 @@ nsDisplayList::ComputeVisibilityForSublist(nsDisplayListBuilder* aBuilder,
if (item->ComputeVisibility(aBuilder, aVisibleRegion)) {
anyVisible = PR_TRUE;
PRBool transparentBackground = PR_FALSE;
if (TreatAsOpaque(item, aBuilder, &transparentBackground)) {
// Subtract opaque item from the visible region
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, nsRegion(bounds));
}
nsRegion opaque = TreatAsOpaque(item, aBuilder, &transparentBackground);
// Subtract opaque item from the visible region
aBuilder->SubtractFromVisibleRegion(aVisibleRegion, opaque);
forceTransparentSurface = forceTransparentSurface || transparentBackground;
}
AppendToBottom(item);
@ -686,9 +688,8 @@ PRBool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
return PR_FALSE;
PRBool forceTransparentBackground;
if (TreatAsOpaque(this, aBuilder, &forceTransparentBackground)) {
aVisibleRegion->Sub(*aVisibleRegion, bounds);
}
nsRegion opaque = TreatAsOpaque(this, aBuilder, &forceTransparentBackground);
aVisibleRegion->Sub(*aVisibleRegion, opaque);
return PR_TRUE;
}
@ -834,25 +835,8 @@ RoundedBorderIntersectsRect(nsIFrame* aFrame,
static PRBool RoundedRectContainsRect(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;
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;
nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(aRoundedRect, aRadii, aContainedRect);
return rgn.Contains(aContainedRect);
}
void
@ -888,9 +872,10 @@ nsDisplayBackground::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC);
}
PRBool
nsDisplayBackground::IsOpaque(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) {
nsRegion
nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) {
nsRegion result;
if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE;
}
@ -901,27 +886,34 @@ nsDisplayBackground::IsOpaque(nsDisplayListBuilder* aBuilder,
*aForceTransparentSurface = disp->mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
disp->mAppearance == NS_THEME_WIN_GLASS;
}
return mThemeTransparency == nsITheme::eOpaque;
if (mThemeTransparency == nsITheme::eOpaque) {
result = GetBounds(aBuilder);
}
return result;
}
nsStyleContext* bgSC;
if (!nsCSSRendering::FindBackground(mFrame->PresContext(), mFrame, &bgSC))
return PR_FALSE;
return result;
const nsStyleBackground* bg = bgSC->GetStyleBackground();
const nsStyleBackground::Layer& bottomLayer = bg->BottomLayer();
// bottom layer's clip is used for the color
if (bottomLayer.mClip != NS_STYLE_BG_CLIP_BORDER ||
nsLayoutUtils::HasNonZeroCorner(mFrame->GetStyleBorder()->mBorderRadius))
return PR_FALSE;
return result;
if (NS_GET_A(bg->mBackgroundColor) == 255 &&
!nsCSSRendering::IsCanvasFrame(mFrame))
return PR_TRUE;
!nsCSSRendering::IsCanvasFrame(mFrame)) {
result = GetBounds(aBuilder);
return result;
}
return bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY &&
bottomLayer.mImage.IsOpaque();
if (bottomLayer.mRepeat == NS_STYLE_BG_REPEAT_XY &&
bottomLayer.mImage.IsOpaque()) {
result = GetBounds(aBuilder);
}
return result;
}
PRBool
@ -1283,13 +1275,17 @@ nsDisplayWrapList::ComputeVisibility(nsDisplayListBuilder* aBuilder,
mVisibleRect);
}
PRBool
nsDisplayWrapList::IsOpaque(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) {
nsRegion
nsDisplayWrapList::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) {
if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE;
}
return mList.IsOpaque();
nsRegion result;
if (mList.IsOpaque()) {
result = GetBounds(aBuilder);
}
return result;
}
PRBool nsDisplayWrapList::IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) {
@ -1427,14 +1423,14 @@ nsDisplayOpacity::~nsDisplayOpacity() {
}
#endif
PRBool nsDisplayOpacity::IsOpaque(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) {
nsRegion nsDisplayOpacity::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface) {
if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE;
}
// We are never opaque, if our opacity was < 1 then we wouldn't have
// been created.
return PR_FALSE;
return nsRegion();
}
// nsDisplayOpacity uses layers for rendering
@ -1601,13 +1597,14 @@ nsDisplayClipRoundedRect::~nsDisplayClipRoundedRect()
}
#endif
PRBool nsDisplayClipRoundedRect::IsOpaque(nsDisplayListBuilder* aBuilder,
nsRegion
nsDisplayClipRoundedRect::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface)
{
if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE;
}
return PR_FALSE;
return nsRegion();
}
void
@ -2021,8 +2018,8 @@ nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder *aBuilder)
* mStoredList.GetVisibleRect().Contains(untransformedVisible), then it
* certainly contains the actual (non-axis-aligned) untransformed rect.
*/
PRBool nsDisplayTransform::IsOpaque(nsDisplayListBuilder *aBuilder,
PRBool* aForceTransparentSurface)
nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
PRBool* aForceTransparentSurface)
{
if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE;
@ -2030,14 +2027,17 @@ PRBool nsDisplayTransform::IsOpaque(nsDisplayListBuilder *aBuilder,
const nsStyleDisplay* disp = mFrame->GetStyleDisplay();
nsRect untransformedVisible =
UntransformRect(mVisibleRect, mFrame, ToReferenceFrame());
return disp->mTransform.GetMainMatrixEntry(1) == 0.0f &&
disp->mTransform.GetMainMatrixEntry(2) == 0.0f &&
mStoredList.GetVisibleRect().Contains(untransformedVisible) &&
mStoredList.IsOpaque(aBuilder);
nsRegion result;
if (disp->mTransform.GetMainMatrixEntry(1) == 0.0f &&
disp->mTransform.GetMainMatrixEntry(2) == 0.0f &&
mStoredList.GetOpaqueRegion(aBuilder).Contains(untransformedVisible)) {
result = mVisibleRect;
}
return result;
}
/* 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.
*/
PRBool nsDisplayTransform::IsUniform(nsDisplayListBuilder *aBuilder, nscolor* aColor)
@ -2161,13 +2161,13 @@ nsDisplaySVGEffects::~nsDisplaySVGEffects()
}
#endif
PRBool nsDisplaySVGEffects::IsOpaque(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface)
nsRegion nsDisplaySVGEffects::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
PRBool* aForceTransparentSurface)
{
if (aForceTransparentSurface) {
*aForceTransparentSurface = PR_FALSE;
}
return PR_FALSE;
return nsRegion();
}
void

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

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

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

@ -178,11 +178,15 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
nscolor color;
nsRect vis = i->GetVisibleRect();
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",
i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
rect.x, rect.y, rect.width, rect.height,
vis.x, vis.y, vis.width, vis.height,
((!list || list->DidComputeVisibility()) && i->IsOpaque(aBuilder)) ? " opaque" : "",
opaque.IsEmpty() ? "" : " opaque",
i->IsUniform(aBuilder, &color) ? " uniform" : "");
if (list) {
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));
}
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
nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
const gfxMatrix &aMatrix, float aFactor)

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

@ -512,6 +512,15 @@ public:
*/
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 {
PAINT_IN_TRANSFORM = 0x01,
PAINT_SYNC_DECODE_IMAGES = 0x02,

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

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

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

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

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

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

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

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

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

@ -375,10 +375,10 @@ public:
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
// 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
// away completely (e.g. because of a decoder error). The problem would
// 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
// percentage unit, which can not be evaluated until the source image size
// 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.
return mType == eStyleImageType_Null;
}