Bug 841192. Part 9: Add extra APIs to DisplayItemClip to set the current state, intersect with another DisplayItemClip, test intersection with a rect, translate, and provide easy access to a DisplayItemClip object which doesn't clip anything. r=mattwoodrow

--HG--
extra : rebase_source : 94b03b7d828c9044ac6ebbeaf51f9f0b4bde1ce2
This commit is contained in:
Robert O'Callahan 2013-03-07 00:08:11 +13:00
parent 37d2be7018
commit 8b148be927
3 changed files with 114 additions and 27 deletions

View File

@ -13,32 +13,41 @@
namespace mozilla {
DisplayItemClip::DisplayItemClip(const DisplayItemClip& aOther, nsDisplayItem* aClipItem)
: mRoundedClipRects(aOther.mRoundedClipRects),
mHaveClipRect(true)
void
DisplayItemClip::SetTo(const nsRect& aRect)
{
nsDisplayItem::Type type = aClipItem->GetType();
NS_ABORT_IF_FALSE(type == nsDisplayItem::TYPE_CLIP ||
type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT,
"unexpected display item type");
nsDisplayClip* item = static_cast<nsDisplayClip*>(aClipItem);
// Always intersect with mClipRect, even if we're going to add a
// rounded rect.
if (aOther.mHaveClipRect) {
mClipRect.IntersectRect(aOther.mClipRect, item->GetClipRect());
} else {
mClipRect = item->GetClipRect();
}
mHaveClipRect = true;
mClipRect = aRect;
mRoundedClipRects.Clear();
}
if (type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) {
RoundedRect *rr = mRoundedClipRects.AppendElement();
if (rr) {
rr->mRect = item->GetClipRect();
static_cast<nsDisplayClipRoundedRect*>(item)->GetRadii(rr->mRadii);
void
DisplayItemClip::SetTo(const nsRect& aRect, const nscoord* aRadii)
{
mHaveClipRect = true;
mClipRect = aRect;
mRoundedClipRects.SetLength(1);
mRoundedClipRects[0].mRect = aRect;
memcpy(mRoundedClipRects[0].mRadii, aRadii, sizeof(nscoord)*8);
}
bool
DisplayItemClip::MayIntersect(const nsRect& aRect) const
{
if (!mHaveClipRect) {
return !aRect.IsEmpty();
}
nsRect r = aRect.Intersect(mClipRect);
if (r.IsEmpty()) {
return false;
}
for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
const RoundedRect& rr = mRoundedClipRects[i];
if (!nsLayoutUtils::RoundedRectIntersectsRect(rr.mRect, rr.mRadii, r)) {
return false;
}
}
// FIXME: Optimize away excess rounded rectangles due to the new addition.
return true;
}
void
@ -124,7 +133,7 @@ DisplayItemClip::AddRoundedRectPathTo(gfxContext* aContext,
}
nsRect
DisplayItemClip::ApproximateIntersect(const nsRect& aRect) const
DisplayItemClip::ApproximateIntersectInward(const nsRect& aRect) const
{
nsRect r = aRect;
if (mHaveClipRect) {
@ -347,4 +356,53 @@ DisplayItemClip::ComputeRegionInClips(DisplayItemClip* aOldClip,
return true;
}
void
DisplayItemClip::MoveBy(nsPoint aPoint)
{
if (!mHaveClipRect)
return;
mClipRect += aPoint;
for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
mRoundedClipRects[i].mRect += aPoint;
}
}
static DisplayItemClip* gNoClip;
const DisplayItemClip&
DisplayItemClip::NoClip()
{
if (!gNoClip) {
gNoClip = new DisplayItemClip();
}
return *gNoClip;
}
void
DisplayItemClip::Shutdown()
{
delete gNoClip;
gNoClip = nullptr;
}
#ifdef DEBUG
nsCString
DisplayItemClip::ToString() const
{
nsAutoCString str;
if (mHaveClipRect) {
str.AppendPrintf("%d,%d,%d,%d", mClipRect.x, mClipRect.y,
mClipRect.width, mClipRect.height);
for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
const RoundedRect& r = mRoundedClipRects[i];
str.AppendPrintf(" [%d,%d,%d,%d corners %d,%d,%d,%d,%d,%d,%d,%d]",
r.mRect.x, r.mRect.y, r.mRect.width, r.mRect.height,
r.mRadii[0], r.mRadii[1], r.mRadii[2], r.mRadii[3],
r.mRadii[4], r.mRadii[5], r.mRadii[6], r.mRadii[7]);
}
}
return str;
}
#endif
}

View File

@ -53,11 +53,18 @@ public:
};
// Constructs a DisplayItemClip that does no clipping at all.
DisplayItemClip() : mHaveClipRect(false) {}
DisplayItemClip() : mHaveClipRect(false), mHasBeenDestroyed(false) {}
~DisplayItemClip() { mHasBeenDestroyed = true; }
// Construct as the intersection of aOther and aClipItem.
DisplayItemClip(const DisplayItemClip& aOther, nsDisplayItem* aClipItem);
void MaybeDestroy() const
{
if (!mHasBeenDestroyed) {
this->~DisplayItemClip();
}
}
void SetTo(const nsRect& aRect);
void SetTo(const nsRect& aRect, const nscoord* aRadii);
void IntersectWith(const DisplayItemClip& aOther);
// Apply this |DisplayItemClip| to the given gfxContext. Any saving of state
@ -80,10 +87,16 @@ public:
void AddRoundedRectPathTo(gfxContext* aContext, int32_t A2D,
const RoundedRect &aRoundRect) const;
// Returns true if the intersection of aRect and this clip region is
// non-empty. This is precise for DisplayItemClips with at most one
// rounded rectangle. When multiple rounded rectangles are present, we just
// check that the rectangle intersects all of them (but possibly in different
// places). So it may return true when the correct answer is false.
bool MayIntersect(const nsRect& aRect) const;
// 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;
nsRect ApproximateIntersectInward(const nsRect& aRect) const;
/*
* Computes a region which contains the clipped area of this DisplayItemClip,
@ -138,6 +151,12 @@ public:
return mClipRect;
}
void MoveBy(nsPoint aPoint);
#ifdef DEBUG
nsCString ToString() const;
#endif
/**
* 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.
@ -147,12 +166,19 @@ public:
uint32_t GetRoundedRectCount() const { return mRoundedClipRects.Length(); }
void AppendRoundedRects(nsTArray<RoundedRect>* aArray, uint32_t aCount) const;
static const DisplayItemClip& NoClip();
static void Shutdown();
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;
// Set to true when the destructor has run. This is a bit of a hack
// to ensure that we can easily share arena-allocated DisplayItemClips.
bool mHasBeenDestroyed;
};
}

View File

@ -60,6 +60,7 @@
#include "nsMathMLOperators.h"
#include "Navigator.h"
#include "nsDOMStorageBaseDB.h"
#include "DisplayItemClip.h"
#include "AudioChannelService.h"
@ -392,5 +393,7 @@ nsLayoutStatics::Shutdown()
nsRefreshDriver::Shutdown();
DisplayItemClip::Shutdown();
nsDocument::XPCOMShutdown();
}