Bug 800859. Part 3: Dispatch MozAfterPaint after we've done the COMPOSITE step for the invalidations recorded in the event. r=mattwoodrow

--HG--
extra : rebase_source : 7a204c0930e7a2a35ad99af79d28ebba56f034fe
This commit is contained in:
Robert O'Callahan 2012-10-19 17:50:34 +13:00
parent 0f08510fc2
commit 4fa3b26bd8
4 changed files with 89 additions and 36 deletions

View File

@ -22,7 +22,7 @@ nsDOMNotifyPaintEvent::nsDOMNotifyPaintEvent(nsPresContext* aPresContext,
mEvent->message = aEventType;
}
if (aInvalidateRequests) {
mInvalidateRequests.SwapElements(aInvalidateRequests->mRequests);
mInvalidateRequests.MoveElementsFrom(aInvalidateRequests->mRequests);
}
}

View File

@ -134,14 +134,15 @@ nsPresContext::MakeColorPref(const nsString& aColor)
bool
nsPresContext::IsDOMPaintEventPending()
{
if (!mInvalidateRequests.mRequests.IsEmpty()) {
return true;
if (mFireAfterPaintEvents) {
return true;
}
if (GetDisplayRootPresContext()->GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) {
// Since we're promising that there will be a MozAfterPaint event
// fired, we record an empty invalidation in case display list
// invalidation doesn't invalidate anything further.
NotifyInvalidation(nsRect(0, 0, 0, 0), 0);
NS_ASSERTION(mFireAfterPaintEvents, "Why aren't we planning to fire the event?");
return true;
}
return false;
@ -2033,7 +2034,7 @@ nsPresContext::EnsureSafeToHandOutCSSRules()
}
void
nsPresContext::FireDOMPaintEvent()
nsPresContext::FireDOMPaintEvent(nsInvalidateRequestList* aList)
{
nsPIDOMWindow* ourWindow = mDocument->GetWindow();
if (!ourWindow)
@ -2058,9 +2059,7 @@ nsPresContext::FireDOMPaintEvent()
// (hopefully it won't, or we're likely to get an infinite loop! At least
// it won't be blocking app execution though).
NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), this, nullptr,
NS_AFTERPAINT,
&mInvalidateRequests);
mAllInvalidated = false;
NS_AFTERPAINT, aList);
if (!event) {
return;
}
@ -2199,7 +2198,7 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags)
}
nsInvalidateRequestList::Request* request =
mInvalidateRequests.mRequests.AppendElement();
mInvalidateRequestsSinceLastPaint.mRequests.AppendElement();
if (!request)
return;
@ -2231,36 +2230,81 @@ nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer,
}
}
struct NotifyDidPaintSubdocumentCallbackClosure {
uint32_t mFlags;
bool mNeedsAnotherDidPaintNotification;
};
static bool
NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData)
{
NotifyDidPaintSubdocumentCallbackClosure* closure =
static_cast<NotifyDidPaintSubdocumentCallbackClosure*>(aData);
nsIPresShell* shell = aDocument->GetShell();
if (shell) {
nsPresContext* pc = shell->GetPresContext();
if (pc) {
pc->NotifyDidPaintForSubtree();
pc->NotifyDidPaintForSubtree(closure->mFlags);
if (pc->IsDOMPaintEventPending()) {
closure->mNeedsAnotherDidPaintNotification = true;
}
}
}
return true;
}
class DelayedFireDOMPaintEvent : public nsRunnable {
public:
DelayedFireDOMPaintEvent(nsPresContext* aPresContext,
nsInvalidateRequestList* aList)
: mPresContext(aPresContext)
{
mList.TakeFrom(aList);
}
NS_IMETHOD Run()
{
mPresContext->FireDOMPaintEvent(&mList);
return NS_OK;
}
nsRefPtr<nsPresContext> mPresContext;
nsInvalidateRequestList mList;
};
void
nsPresContext::NotifyDidPaintForSubtree()
nsPresContext::NotifyDidPaintForSubtree(uint32_t aFlags)
{
if (IsRoot()) {
if (!mFireAfterPaintEvents)
return;
static_cast<nsRootPresContext*>(this)->CancelDidPaintTimer();
}
mFireAfterPaintEvents = false;
if (!mFireAfterPaintEvents) {
return;
}
nsCOMPtr<nsIRunnable> ev =
NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent);
nsContentUtils::AddScriptRunner(ev);
if (aFlags & nsIPresShell::PAINT_LAYERS) {
mUndeliveredInvalidateRequestsBeforeLastPaint.TakeFrom(
&mInvalidateRequestsSinceLastPaint);
mAllInvalidated = false;
}
if (aFlags & nsIPresShell::PAINT_COMPOSITE) {
nsCOMPtr<nsIRunnable> ev =
new DelayedFireDOMPaintEvent(this, &mUndeliveredInvalidateRequestsBeforeLastPaint);
nsContentUtils::AddScriptRunner(ev);
}
mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, nullptr);
NotifyDidPaintSubdocumentCallbackClosure closure = { aFlags, false };
mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, &closure);
if (!closure.mNeedsAnotherDidPaintNotification &&
mInvalidateRequestsSinceLastPaint.IsEmpty() &&
mUndeliveredInvalidateRequestsBeforeLastPaint.IsEmpty()) {
// Nothing more to do for the moment.
mFireAfterPaintEvents = false;
} else {
if (IsRoot()) {
static_cast<nsRootPresContext*>(this)->EnsureEventualDidPaintEvent();
}
}
}
bool
@ -2725,7 +2769,10 @@ NotifyDidPaintForSubtreeCallback(nsITimer *aTimer, void *aClosure)
{
nsPresContext* presContext = (nsPresContext*)aClosure;
nsAutoScriptBlocker blockScripts;
presContext->NotifyDidPaintForSubtree();
// This is a fallback if we don't get paint events for some reason
// so we'll just pretend both layer painting and compositing happened.
presContext->NotifyDidPaintForSubtree(
nsIPresShell::PAINT_LAYERS | nsIPresShell::PAINT_COMPOSITE);
}
void

View File

@ -110,6 +110,12 @@ public:
uint32_t mFlags;
};
void TakeFrom(nsInvalidateRequestList* aList)
{
mRequests.MoveElementsFrom(aList->mRequests);
}
bool IsEmpty() { return mRequests.IsEmpty(); }
nsTArray<Request> mRequests;
};
@ -828,8 +834,9 @@ public:
void NotifyInvalidation(const nsRect& aRect, uint32_t aFlags);
// aRect is in device pixels
void NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags);
void NotifyDidPaintForSubtree();
void FireDOMPaintEvent();
// aFlags are nsIPresShell::PAINT_ flags
void NotifyDidPaintForSubtree(uint32_t aFlags);
void FireDOMPaintEvent(nsInvalidateRequestList* aList);
// Callback for catching invalidations in ContainerLayers
// Passed to LayerProperties::ComputeDifference
@ -837,7 +844,8 @@ public:
const nsIntRegion& aRegion);
bool IsDOMPaintEventPending();
void ClearMozAfterPaintEvents() {
mInvalidateRequests.mRequests.Clear();
mInvalidateRequestsSinceLastPaint.mRequests.Clear();
mUndeliveredInvalidateRequestsBeforeLastPaint.mRequests.Clear();
mAllInvalidated = false;
}
@ -1138,7 +1146,8 @@ protected:
FramePropertyTable mPropertyTable;
nsInvalidateRequestList mInvalidateRequests;
nsInvalidateRequestList mInvalidateRequestsSinceLastPaint;
nsInvalidateRequestList mUndeliveredInvalidateRequestsBeforeLastPaint;
// container for per-context fonts (downloadable, SVG, etc.)
nsUserFontSet* mUserFontSet;
@ -1200,6 +1209,8 @@ protected:
unsigned mPendingMediaFeatureValuesChanged : 1;
unsigned mPrefChangePendingNeedsReflow : 1;
unsigned mMayHaveFixedBackgroundFrames : 1;
// True if the requests in mInvalidateRequestsSinceLastPaint cover the
// entire viewport
unsigned mAllInvalidated : 1;
// Are we currently drawing an SVG glyph?

View File

@ -5216,19 +5216,22 @@ PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
class nsAutoNotifyDidPaint
{
public:
nsAutoNotifyDidPaint(bool aWillSendDidPaint)
: mWillSendDidPaint(aWillSendDidPaint)
nsAutoNotifyDidPaint(PresShell* aShell, uint32_t aFlags)
: mShell(aShell), mFlags(aFlags)
{
}
~nsAutoNotifyDidPaint()
{
if (!mWillSendDidPaint && nsContentUtils::XPConnect()) {
mShell->GetPresContext()->NotifyDidPaintForSubtree(mFlags);
if (!(mFlags & nsIPresShell::PAINT_WILL_SEND_DID_PAINT) &&
nsContentUtils::XPConnect()) {
nsContentUtils::XPConnect()->NotifyDidPaint();
}
}
private:
bool mWillSendDidPaint;
PresShell* mShell;
uint32_t mFlags;
};
void
@ -5240,7 +5243,7 @@ PresShell::Paint(nsIView* aViewToPaint,
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
NS_ASSERTION(aViewToPaint, "null view");
nsAutoNotifyDidPaint notifyDidPaint((aFlags & PAINT_WILL_SEND_DID_PAINT) != 0);
nsAutoNotifyDidPaint notifyDidPaint(this, aFlags);
nsPresContext* presContext = GetPresContext();
AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
@ -5309,7 +5312,6 @@ PresShell::Paint(nsIView* aViewToPaint,
}
frame->UpdatePaintCountForPaintedPresShells();
presContext->NotifyDidPaintForSubtree();
return;
}
}
@ -5338,9 +5340,6 @@ PresShell::Paint(nsIView* aViewToPaint,
nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor, flags);
frame->EndDeferringInvalidatesForDisplayRoot();
if (aFlags & PAINT_LAYERS) {
presContext->NotifyDidPaintForSubtree();
}
return;
}
@ -5356,10 +5355,6 @@ PresShell::Paint(nsIView* aViewToPaint,
}
layerManager->EndTransaction(NULL, NULL, (aFlags & PAINT_COMPOSITE) ?
LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE);
if (aFlags & PAINT_LAYERS) {
presContext->NotifyDidPaintForSubtree();
}
}
// static