From 7e9c8ecff43e2824104903c5eec7e507340d92a3 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Fri, 23 Dec 2011 22:52:24 -0500 Subject: [PATCH] Bug 598482 part 18 - Separate NS_WILL_PAINT and NS_PAINT handling; only flush again if no NS_WILL_PAINT event has been sent by the platform. r=roc --- view/src/nsViewManager.cpp | 92 +++++++++++++++------------------- widget/cocoa/nsChildView.mm | 1 + widget/nsGUIEvent.h | 4 +- widget/windows/nsWindowGfx.cpp | 1 + 4 files changed, 46 insertions(+), 52 deletions(-) diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index a755da5f18c..4103175dbed 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -753,34 +753,20 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, break; case NS_WILL_PAINT: - case NS_PAINT: { - nsPaintEvent *event = static_cast(aEvent); - if (!aView || !mContext) break; *aStatus = nsEventStatus_eConsumeNoDefault; - if (aEvent->message == NS_PAINT && event->region.IsEmpty()) - break; + nsPaintEvent *event = static_cast(aEvent); NS_ASSERTION(static_cast(aView) == nsView::GetViewFor(event->widget), "view/widget mismatch"); - // The region is in device units, and it's in the coordinate space of - // its associated widget. - - // Refresh the view - NS_ASSERTION(IsPaintingAllowed(), - "shouldn't be receiving paint events while painting is " - "disallowed!"); - nsRefPtr rootVM = RootViewManager(); - // If an ancestor widget was hidden and then shown, we could // have a delayed resize to handle. - bool didResize = false; for (nsViewManager *vm = this; vm; vm = vm->mRootView->GetParent() ? vm->mRootView->GetParent()->GetViewManager() @@ -789,47 +775,51 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, vm->mRootView->IsEffectivelyVisible() && mPresShell && mPresShell->IsVisible()) { vm->FlushDelayedResize(true); - - // Paint later. vm->UpdateView(vm->mRootView); - didResize = true; - - // not sure if it's valid for us to claim that we - // ignored this, but we're going to do so anyway, since - // we didn't actually paint anything - *aStatus = nsEventStatus_eIgnore; } } - if (!didResize) { - // Notify view observers that we're about to paint. - // Make sure to not send WillPaint notifications while scrolling. - - nsCOMPtr widget; - rootVM->GetRootWidget(getter_AddRefs(widget)); - bool transparentWindow = false; - if (widget) - transparentWindow = widget->GetTransparencyMode() == eTransparencyTransparent; - - nsView* view = static_cast(aView); - if (!transparentWindow) { - if (mPresShell) { - rootVM->CallWillPaintOnObservers(event->willSendDidPaint); - // Get the view pointer again since the code above might have - // destroyed it (bug 378273). - view = nsView::GetViewFor(aEvent->widget); - } - } - // Make sure to sync up any widget geometry changes we - // have pending before we paint. - if (rootVM->mHasPendingUpdates) { - rootVM->ProcessPendingUpdatesForView(mRootView); - } - - if (view && aEvent->message == NS_PAINT) { - Refresh(view, event->widget, event->region); - } + // Flush things like reflows and plugin widget geometry updates by + // calling WillPaint on observer presShells. + nsRefPtr rootVM = RootViewManager(); + if (mPresShell) { + rootVM->CallWillPaintOnObservers(event->willSendDidPaint); } + // Flush view widget geometry updates and invalidations. + rootVM->ProcessPendingUpdates(); + } + break; + + case NS_PAINT: + { + if (!aView || !mContext) + break; + + *aStatus = nsEventStatus_eConsumeNoDefault; + nsPaintEvent *event = static_cast(aEvent); + nsView* view = static_cast(aView); + NS_ASSERTION(view == nsView::GetViewFor(event->widget), + "view/widget mismatch"); + NS_ASSERTION(IsPaintingAllowed(), + "shouldn't be receiving paint events while painting is " + "disallowed!"); + + if (!event->didSendWillPaint) { + // Send NS_WILL_PAINT event ourselves. + nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget); + willPaintEvent.willSendDidPaint = event->willSendDidPaint; + DispatchEvent(&willPaintEvent, view, aStatus); + + // Get the view pointer again since NS_WILL_PAINT might have + // destroyed it during CallWillPaintOnObservers (bug 378273). + view = nsView::GetViewFor(event->widget); + } + + if (!view || event->region.IsEmpty()) + break; + + // Paint. + Refresh(view, event->widget, event->region); break; } diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index d934fe5d758..8c53926c631 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -2508,6 +2508,7 @@ NSEvent* gLastDragMouseDownEvent = nil; #endif // Create the event so we can fill in its region nsPaintEvent paintEvent(true, NS_PAINT, mGeckoChild); + paintEvent.didSendWillPaint = true; nsIntRect boundingRect = nsIntRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height); diff --git a/widget/nsGUIEvent.h b/widget/nsGUIEvent.h index 4aaa498ec0f..13a24f5cdeb 100644 --- a/widget/nsGUIEvent.h +++ b/widget/nsGUIEvent.h @@ -737,13 +737,15 @@ class nsPaintEvent : public nsGUIEvent public: nsPaintEvent(bool isTrusted, PRUint32 msg, nsIWidget *w) : nsGUIEvent(isTrusted, msg, w, NS_PAINT_EVENT), - willSendDidPaint(false) + willSendDidPaint(false), + didSendWillPaint(false) { } // area that needs repainting nsIntRegion region; bool willSendDidPaint; + bool didSendWillPaint; }; /** diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index c6c71913005..02a613077d7 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -312,6 +312,7 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32 aNestingLevel) #endif event.region = GetRegionToPaint(forceRepaint, ps, hDC); event.willSendDidPaint = true; + event.didSendWillPaint = true; if (!event.region.IsEmpty() && mEventCallback) {