зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
e6d799410e
Коммит
d5101880c0
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче