mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-15 06:15:43 +00:00
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:
parent
37d2be7018
commit
8b148be927
@ -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
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user