Bug 841192. Part 3: Make DisplayItemClip members private and encapsulate them in a real API. r=mattwoodrow

--HG--
extra : rebase_source : d6076e123603de9a1c48681f527719cd41b09883
This commit is contained in:
Robert O'Callahan 2013-03-04 22:56:00 +13:00
Родитель e6d799410e
Коммит d5101880c0
3 изменённых файлов: 130 добавлений и 81 удалений

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

@ -207,6 +207,23 @@ DisplayItemClip::NonRoundedIntersection() const
return result;
}
bool
DisplayItemClip::IsRectAffectedByClip(const nsRect& aRect) const
{
if (mHaveClipRect && !mClipRect.Contains(aRect)) {
return true;
}
for (uint32_t i = 0, iEnd = mRoundedClipRects.Length();
i < iEnd; ++i) {
const RoundedRect &rr = mRoundedClipRects[i];
nsRegion rgn = nsLayoutUtils::RoundedRectIntersectRect(rr.mRect, rr.mRadii, aRect);
if (!rgn.Contains(aRect)) {
return true;
}
}
return false;
}
nsRect
DisplayItemClip::ApplyNonRoundedIntersection(const nsRect& aRect) const
{
@ -269,4 +286,48 @@ DisplayItemClip::AddOffsetAndComputeDifference(const nsPoint& aOffset,
}
}
uint32_t
DisplayItemClip::GetCommonRoundedRectCount(const DisplayItemClip& aOther,
uint32_t aMax) const
{
uint32_t end = std::min(std::min(mRoundedClipRects.Length(), aMax),
aOther.mRoundedClipRects.Length());
uint32_t clipCount = 0;
for (; clipCount < end; ++clipCount) {
if (mRoundedClipRects[clipCount] !=
aOther.mRoundedClipRects[clipCount]) {
return clipCount;
}
}
return clipCount;
}
void
DisplayItemClip::AppendRoundedRects(nsTArray<RoundedRect>* aArray, uint32_t aCount) const
{
uint32_t count = std::min(mRoundedClipRects.Length(), aCount);
for (uint32_t i = 0; i < count; ++i) {
*aArray->AppendElement() = mRoundedClipRects[i];
}
}
bool
DisplayItemClip::ComputeRegionInClips(DisplayItemClip* aOldClip,
const nsPoint& aShift,
nsRegion* aCombined) const
{
if (!mHaveClipRect || (aOldClip && !aOldClip->mHaveClipRect)) {
return false;
}
if (aOldClip) {
*aCombined = aOldClip->NonRoundedIntersection();
aCombined->MoveBy(aShift);
aCombined->Or(*aCombined, NonRoundedIntersection());
} else {
*aCombined = NonRoundedIntersection();
}
return true;
}
}

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

@ -23,7 +23,8 @@ namespace mozilla {
* It can represent everything CSS clipping can do to an element (except for
* SVG clip-path), including no clipping at all.
*/
struct DisplayItemClip {
class DisplayItemClip {
public:
struct RoundedRect {
nsRect mRect;
// Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
@ -50,9 +51,6 @@ struct DisplayItemClip {
return !(*this == aOther);
}
};
nsRect mClipRect;
nsTArray<RoundedRect> mRoundedClipRects;
bool mHaveClipRect;
// Constructs a DisplayItemClip that does no clipping at all.
DisplayItemClip() : mHaveClipRect(false) {}
@ -85,12 +83,27 @@ struct DisplayItemClip {
// not succeed.
nsRect ApproximateIntersect(const nsRect& aRect) const;
/*
* Computes a region which contains the clipped area of this DisplayItemClip,
* or if aOldClip is non-null, the union of the clipped area of this
* DisplayItemClip with the clipped area of aOldClip translated by aShift.
* The result is stored in aCombined. If the result would be infinite
* (because one or both of the clips does no clipping), returns false.
*/
bool ComputeRegionInClips(DisplayItemClip* aOldClip,
const nsPoint& aShift,
nsRegion* aCombined) const;
// Returns false if aRect is definitely not clipped by a rounded corner in
// this clip. Returns true if aRect is clipped by a rounded corner in this
// clip or it can not be quickly determined that it is not clipped by a
// rounded corner in this clip.
bool IsRectClippedByRoundedCorner(const nsRect& aRect) const;
// Returns false if aRect is definitely not clipped by anything in this clip.
// Fast but not necessarily accurate.
bool IsRectAffectedByClip(const nsRect& aRect) const;
// Intersection of all rects in this clip ignoring any rounded corners.
nsRect NonRoundedIntersection() const;
@ -115,6 +128,29 @@ struct DisplayItemClip {
bool operator!=(const DisplayItemClip& aOther) const {
return !(*this == aOther);
}
bool HasClip() { return mHaveClipRect; }
const nsRect& GetClipRect()
{
NS_ASSERTION(HasClip(), "No clip rect!");
return mClipRect;
}
/**
* Find the largest N such that the first N rounded rects in 'this' are
* equal to the first N rounded rects in aOther, and N <= aMax.
*/
uint32_t GetCommonRoundedRectCount(const DisplayItemClip& aOther,
uint32_t aMax) const;
uint32_t GetRoundedRectCount() const { return mRoundedClipRects.Length(); }
void AppendRoundedRects(nsTArray<RoundedRect>* aArray, uint32_t aCount) const;
private:
nsRect mClipRect;
nsTArray<RoundedRect> mRoundedClipRects;
// If mHaveClipRect is false then this object represents no clipping at all
// and mRoundedClipRects must be empty.
bool mHaveClipRect;
};
}

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

@ -108,8 +108,7 @@ FrameLayerBuilder::DisplayItemData::UpdateContents(Layer* aLayer, LayerState aSt
mLayerState = aState;
mContainerLayerGeneration = aContainerLayerGeneration;
mGeometry = nullptr;
mClip.mHaveClipRect = false;
mClip.mRoundedClipRects.Clear();
mClip = DisplayItemClip();
mUsed = true;
if (!aItem) {
@ -1523,21 +1522,10 @@ ContainerState::ThebesLayerData::UpdateCommonClipCount(
const DisplayItemClip& aCurrentClip)
{
if (mCommonClipCount >= 0) {
int32_t end = std::min<int32_t>(aCurrentClip.mRoundedClipRects.Length(),
mCommonClipCount);
int32_t clipCount = 0;
for (; clipCount < end; ++clipCount) {
if (mItemClip.mRoundedClipRects[clipCount] !=
aCurrentClip.mRoundedClipRects[clipCount]) {
break;
}
}
mCommonClipCount = clipCount;
NS_ASSERTION(mItemClip.mRoundedClipRects.Length() >= uint32_t(mCommonClipCount),
"Inconsistent common clip count.");
mCommonClipCount = mItemClip.GetCommonRoundedRectCount(aCurrentClip, mCommonClipCount);
} else {
// first item in the layer
mCommonClipCount = aCurrentClip.mRoundedClipRects.Length();
mCommonClipCount = aCurrentClip.GetRoundedRectCount();
}
}
@ -1572,8 +1560,8 @@ ContainerState::PopThebesLayerData()
data->mImage->ConfigureLayer(imageLayer, mParameters.mOffset);
imageLayer->SetPostScale(mParameters.mXScale,
mParameters.mYScale);
if (data->mItemClip.mHaveClipRect) {
nsIntRect clip = ScaleToNearestPixels(data->mItemClip.mClipRect);
if (data->mItemClip.HasClip()) {
nsIntRect clip = ScaleToNearestPixels(data->mItemClip.GetClipRect());
clip.MoveBy(mParameters.mOffset);
imageLayer->SetClipRect(&clip);
} else {
@ -1794,7 +1782,7 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
isUniform = false;
}
}
if (isUniform && aClip.mRoundedClipRects.IsEmpty()) {
if (isUniform && aClip.GetRoundedRectCount() == 0) {
if (mVisibleRegion.IsEmpty()) {
// This color is all we have
mSolidColor = uniformColor;
@ -2091,8 +2079,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
nsRect itemContent = item->GetBounds(mBuilder, &snap);
nsIntRect itemDrawRect = ScaleToOutsidePixels(itemContent, snap);
nsIntRect clipRect;
if (aClip.mHaveClipRect) {
itemContent.IntersectRect(itemContent, aClip.mClipRect);
if (aClip.HasClip()) {
itemContent.IntersectRect(itemContent, aClip.GetClipRect());
clipRect = ScaleToNearestPixels(aClip.NonRoundedIntersection());
itemDrawRect.IntersectRect(itemDrawRect, clipRect);
clipRect.MoveBy(mParameters.mOffset);
@ -2188,11 +2176,11 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
"We shouldn't have a FrameLayerBuilder-managed layer here!");
NS_ASSERTION(aClip.mHaveClipRect ||
aClip.mRoundedClipRects.IsEmpty(),
NS_ASSERTION(aClip.HasClip() ||
aClip.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.mHaveClipRect) {
if (aClip.HasClip()) {
ownLayer->SetClipRect(&clipRect);
} else {
ownLayer->SetClipRect(nullptr);
@ -2260,37 +2248,6 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
}
}
/**
* Combine two clips and returns true if clipping
* needs to be applied.
*
* @param aClip Current clip
* @param aOldClip Optional clip from previous paint.
* @param aShift Offet to apply to aOldClip
* @param aCombined Outparam - Computed clip region
* @return True if the clip should be applied, false
* otherwise.
*/
static bool ComputeCombinedClip(const DisplayItemClip& aClip,
DisplayItemClip* aOldClip,
const nsPoint& aShift,
nsRegion& aCombined)
{
if (!aClip.mHaveClipRect ||
(aOldClip && !aOldClip->mHaveClipRect)) {
return false;
}
if (aOldClip) {
aCombined = aOldClip->NonRoundedIntersection();
aCombined.MoveBy(aShift);
aCombined.Or(aCombined, aClip.NonRoundedIntersection());
} else {
aCombined = aClip.NonRoundedIntersection();
}
return true;
}
void
ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
Layer* aNewLayer,
@ -2385,7 +2342,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
// Restrict invalidation to the clipped region
nsRegion clip;
if (ComputeCombinedClip(aClip, oldClip, shift, clip)) {
if (aClip.ComputeRegionInClips(oldClip, shift, &clip)) {
combined.And(combined, clip);
}
#ifdef DEBUG_INVALIDATIONS
@ -2429,9 +2386,9 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
nsRegion clip;
DisplayItemClip* oldClip = nullptr;
GetOldLayerFor(aItem, nullptr, &oldClip);
hasClip = ComputeCombinedClip(aClip, oldClip,
aTopLeft - thebesData->mLastActiveScrolledRootOrigin,
clip);
hasClip = aClip.ComputeRegionInClips(oldClip,
aTopLeft - thebesData->mLastActiveScrolledRootOrigin,
&clip);
if (hasClip) {
intClip = clip.GetBounds().ScaleToOutsidePixels(thebesData->mXScale,
@ -3283,13 +3240,11 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
NS_ASSERTION(AppUnitsPerDevPixel(cdi->mItem) == appUnitsPerDevPixel,
"a thebes layer should contain items only at the same zoom");
NS_ABORT_IF_FALSE(cdi->mClip.mHaveClipRect ||
cdi->mClip.mRoundedClipRects.IsEmpty(),
NS_ABORT_IF_FALSE(cdi->mClip.HasClip() ||
cdi->mClip.GetRoundedRectCount() == 0,
"If we have rounded rects, we must have a clip rect");
if (!cdi->mClip.mHaveClipRect ||
(cdi->mClip.mRoundedClipRects.IsEmpty() &&
cdi->mClip.mClipRect.Contains(visible.GetBounds()))) {
if (!cdi->mClip.IsRectAffectedByClip(visible.GetBounds())) {
cdi->mItem->RecomputeVisibility(builder, &visible);
continue;
}
@ -3297,12 +3252,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.mClipRect);
clipped.And(visible, cdi->mClip.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.mRoundedClipRects.IsEmpty()) {
if (cdi->mClip.GetRoundedRectCount() == 0) {
nsRegion removed;
removed.Sub(clipped, finalClipped);
nsRegion newVisible;
@ -3321,7 +3276,7 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
rc->Init(presContext->DeviceContext(), aContext);
DisplayItemClip currentClip;
bool setClipRect = false;
bool currentClipIsSetInContext = false;
for (i = 0; i < items.Length(); ++i) {
ClippedDisplayItem* cdi = &items[i];
@ -3331,13 +3286,13 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
// If the new desired clip state is different from the current state,
// update the clip.
if (setClipRect != cdi->mClip.mHaveClipRect ||
(cdi->mClip.mHaveClipRect && cdi->mClip != currentClip)) {
if (setClipRect) {
if (currentClipIsSetInContext != cdi->mClip.HasClip() ||
(cdi->mClip.HasClip() && cdi->mClip != currentClip)) {
if (currentClipIsSetInContext) {
aContext->Restore();
}
setClipRect = cdi->mClip.mHaveClipRect;
if (setClipRect) {
currentClipIsSetInContext = cdi->mClip.HasClip();
if (currentClipIsSetInContext) {
currentClip = cdi->mClip;
aContext->Save();
NS_ASSERTION(commonClipCount < 100,
@ -3375,7 +3330,7 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
items.SwapElements(entry->mItems);
}
if (setClipRect) {
if (currentClipIsSetInContext) {
aContext->Restore();
}
@ -3450,7 +3405,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
// don't build an unnecessary mask
nsIntRect layerBounds = aLayer->GetVisibleRegion().GetBounds();
if (aClip.mRoundedClipRects.IsEmpty() ||
if (aClip.GetRoundedRectCount() == 0 ||
aRoundedRectClipCount == 0 ||
layerBounds.IsEmpty()) {
SetClipCount(thebesData, 0);
@ -3462,10 +3417,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip,
MaskLayerUserData* userData = GetMaskLayerUserData(maskLayer);
MaskLayerUserData newData;
newData.mRoundedClipRects.AppendElements(aClip.mRoundedClipRects);
if (aRoundedRectClipCount < newData.mRoundedClipRects.Length()) {
newData.mRoundedClipRects.TruncateLength(aRoundedRectClipCount);
}
aClip.AppendRoundedRects(&newData.mRoundedClipRects, aRoundedRectClipCount);
newData.mScaleX = mParameters.mXScale;
newData.mScaleY = mParameters.mYScale;
newData.mOffset = mParameters.mOffset;