Bug 626245. Part 4.5: Forward WillPaintWindow/DidPaintWindow notifications to the presshell and do plugin geometry updates from there. r=matspal
authorRobert O'Callahan <robert@ocallahan.org>
Wed, 10 Oct 2012 23:25:57 +1300
changeset 110323 eed1630b856f7857a8bc91d4979d0c852125fc90
parent 110322 be09855c0f5cc50154dfff3578730742ef49dd87
child 110324 b78108ed9da38e40bb935fe37f79e348e9b40da1
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersmatspal
bugs626245
milestone19.0a1
Bug 626245. Part 4.5: Forward WillPaintWindow/DidPaintWindow notifications to the presshell and do plugin geometry updates from there. r=matspal
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
view/src/nsViewManager.cpp
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -109,20 +109,20 @@ typedef struct CapturingContentInfo {
   // capture should only be allowed during a mousedown event
   bool mAllowed;
   bool mPointerLock;
   bool mRetargetToElement;
   bool mPreventDrag;
   nsIContent* mContent;
 } CapturingContentInfo;
 
-// 7E29E8A8-9C77-4445-A523-41B363E0C98A
+// ebc1bbe4-5456-4c62-ba1f-c2ef7387963e
 #define NS_IPRESSHELL_IID \
-  { 0x7e29e8a8, 0x9c77, 0x4445, \
-    { 0xa5, 0x23, 0x41, 0xb3, 0x63, 0xe0, 0xc9, 0x8a } }
+{ 0xebc1bbe4, 0x5456, 0x4c62, \
+  { 0xba, 0x1f, 0xc2, 0xef, 0x73, 0x87, 0x96, 0x3e } }
 
 // debug VerifyReflow flags
 #define VERIFY_REFLOW_ON                    0x01
 #define VERIFY_REFLOW_NOISY                 0x02
 #define VERIFY_REFLOW_ALL                   0x04
 #define VERIFY_REFLOW_DUMP_COMMANDS         0x08
 #define VERIFY_REFLOW_NOISY_RC              0x10
 #define VERIFY_REFLOW_REALLY_NOISY_RC       0x20
@@ -1225,25 +1225,39 @@ public:
   virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
                      PaintType aType, bool aWillSendDidPaint) = 0;
   virtual nsresult HandleEvent(nsIFrame*       aFrame,
                                nsGUIEvent*     aEvent,
                                bool            aDontRetargetEvents,
                                nsEventStatus*  aEventStatus) = 0;
   virtual bool ShouldIgnoreInvalidation() = 0;
   /**
-   * Notify that the NS_WILL_PAINT event was received. Fires on every
-   * visible presshell in the document tree.
+   * Notify that we're going to call Paint with PaintType_NoComposite
+   * or PaintType_Full on the root pres shell (which might not be this one, since
+   * WillPaint is called on all descendant presshells). This is issued at a time when
+   * it's safe to modify widget geometry.
    */
   virtual void WillPaint(bool aWillSendDidPaint) = 0;
   /**
-   * Notify that the NS_DID_PAINT event was received. Only fires on the
-   * root pres shell.
+   * Notify that we called Paint with PaintType_NoComposite. Only fires on the
+   * root pres shell. This is issued at a time when it's safe to modify
+   * widget geometry.
    */
   virtual void DidPaint() = 0;
+  /**
+   * Notify that we're going to call Paint with PaintType_Composite
+   * or PaintType_Full.  This is issued at a time when it's safe to
+   * modify widget geometry.
+   */
+  virtual void WillPaintWindow(bool aWillSendDidPaint) = 0;
+  /**
+   * Notify that we called Paint with PaintType_Composite or PaintType_Full.
+   * This is issued at a time when it's safe to modify widget geometry.
+   */
+  virtual void DidPaintWindow() = 0;
 
   /**
    * Ensures that the refresh driver is running, and schedules a view 
    * manager flush on the next tick.
    */
   virtual void ScheduleViewManagerFlush() = 0;
   virtual void ClearMouseCaptureOnView(nsIView* aView) = 0;
   virtual bool IsVisible() = 0;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6975,56 +6975,72 @@ bool
 PresShell::ShouldIgnoreInvalidation()
 {
   return mPaintingSuppressed || !mIsActive;
 }
 
 void
 PresShell::WillPaint(bool aWillSendDidPaint)
 {
+  nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
+  if (!rootPresContext) {
+    // In some edge cases, such as when we don't have a root frame yet,
+    // we can't find the root prescontext. There's nothing to do in that
+    // case.
+    return;
+  }
+
   // Don't bother doing anything if some viewmanager in our tree is painting
   // while we still have painting suppressed or we are not active.
   if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
     return;
   }
 
-  nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
-  if (!rootPresContext) {
-    return;
-  }
-
-  if (!aWillSendDidPaint && rootPresContext == mPresContext) {
-    rootPresContext->ApplyPluginGeometryUpdates();
-  }
   rootPresContext->FlushWillPaintObservers();
   if (mIsDestroying)
     return;
 
   // Process reflows, if we have them, to reduce flicker due to invalidates and
   // reflow being interspersed.  Note that we _do_ allow this to be
   // interruptible; if we can't do all the reflows it's better to flicker a bit
   // than to freeze up.
   FlushPendingNotifications(Flush_InterruptibleLayout);
 }
 
 void
 PresShell::DidPaint()
 {
-  if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
+}
+
+void
+PresShell::WillPaintWindow(bool aWillSendDidPaint)
+{
+  nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
+  if (rootPresContext != mPresContext) {
+    // This could be a popup's presshell. We don't allow plugins in popups
+    // so there's nothing to do here.
     return;
   }
 
-  NS_ASSERTION(mPresContext->IsRoot(), "Should only call DidPaint on root presshells");
-
+  if (!aWillSendDidPaint) {
+    rootPresContext->ApplyPluginGeometryUpdates();
+  }
+}
+
+void
+PresShell::DidPaintWindow()
+{
   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
-  // This should only be called on root presshells, but maybe if a document
-  // tree is torn down we might not be a root presshell...
-  if (rootPresContext == mPresContext) {
-    rootPresContext->ApplyPluginGeometryUpdates();
-  }
+  if (rootPresContext != mPresContext) {
+    // This could be a popup's presshell. We don't allow plugins in popups
+    // so there's nothing to do here.
+    return;
+  }
+
+  rootPresContext->ApplyPluginGeometryUpdates();
 
   if (nsContentUtils::XPConnect()) {
     nsContentUtils::XPConnect()->NotifyDidPaint();
   }
 }
 
 bool
 PresShell::IsVisible()
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -192,16 +192,18 @@ public:
                                                         nsEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual NS_HIDDEN_(nsresult) HandleDOMEventWithTarget(nsIContent* aTargetContent,
                                                         nsIDOMEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual bool ShouldIgnoreInvalidation();
   virtual void WillPaint(bool aWillSendDidPaint);
   virtual void DidPaint();
+  virtual void WillPaintWindow(bool aWillSendDidPaint);
+  virtual void DidPaintWindow();
   virtual void ScheduleViewManagerFlush();
   virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange);
   virtual void ClearMouseCaptureOnView(nsIView* aView);
   virtual bool IsVisible();
 
   // caret handling
   virtual NS_HIDDEN_(already_AddRefed<nsCaret>) GetCaret() const;
   virtual NS_HIDDEN_(void) MaybeInvalidateCaretPosition();
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -648,45 +648,43 @@ void nsViewManager::InvalidateViews(nsVi
   while (nullptr != childView)  {
     childView->GetViewManager()->InvalidateViews(childView);
     childView = childView->GetNextSibling();
   }
 }
 
 void nsViewManager::WillPaintWindow(nsIWidget* aWidget, bool aWillSendDidPaint)
 {
-  if (IsRefreshDriverPaintingEnabled())
-    return;
-
-  if (!aWidget || !mContext)
-    return;
+  if (!IsRefreshDriverPaintingEnabled() && aWidget && mContext) {
+    // If an ancestor widget was hidden and then shown, we could
+    // have a delayed resize to handle.
+    for (nsViewManager *vm = this; vm;
+         vm = vm->mRootView->GetParent()
+                ? vm->mRootView->GetParent()->GetViewManager()
+                : nullptr) {
+      if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
+          vm->mRootView->IsEffectivelyVisible() &&
+          mPresShell && mPresShell->IsVisible()) {
+        vm->FlushDelayedResize(true);
+        vm->InvalidateView(vm->mRootView);
+      }
+    }
 
-  // If an ancestor widget was hidden and then shown, we could
-  // have a delayed resize to handle.
-  for (nsViewManager *vm = this; vm;
-       vm = vm->mRootView->GetParent()
-              ? vm->mRootView->GetParent()->GetViewManager()
-              : nullptr) {
-    if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
-        vm->mRootView->IsEffectivelyVisible() &&
-        mPresShell && mPresShell->IsVisible()) {
-      vm->FlushDelayedResize(true);
-      vm->InvalidateView(vm->mRootView);
-    }
+    // Flush things like reflows by calling WillPaint on observer presShells.
+    nsRefPtr<nsViewManager> rootVM = RootViewManager();
+    rootVM->CallWillPaintOnObservers(aWillSendDidPaint);
+
+    // Flush view widget geometry updates and invalidations.
+    rootVM->ProcessPendingUpdates();
   }
 
-  // Flush things like reflows and plugin widget geometry updates by
-  // calling WillPaint on observer presShells.
-  nsRefPtr<nsViewManager> rootVM = RootViewManager();
-  if (mPresShell) {
-    rootVM->CallWillPaintOnObservers(aWillSendDidPaint);
+  nsCOMPtr<nsIPresShell> shell = mPresShell;
+  if (shell) {
+    shell->WillPaintWindow(aWillSendDidPaint);
   }
-
-  // Flush view widget geometry updates and invalidations.
-  rootVM->ProcessPendingUpdates();
 }
 
 bool nsViewManager::PaintWindow(nsIWidget* aWidget, nsIntRegion aRegion,
                                 bool aSentWillPaint, bool aWillSendDidPaint)
  {
   if (!aWidget || !mContext)
     return false;
 
@@ -704,16 +702,21 @@ bool nsViewManager::PaintWindow(nsIWidge
     Refresh(view, aRegion, aWillSendDidPaint);
   }
 
   return true;
 }
 
 void nsViewManager::DidPaintWindow()
 {
+  nsCOMPtr<nsIPresShell> shell = mPresShell;
+  if (shell) {
+    shell->DidPaintWindow();
+  }
+
   if (!IsRefreshDriverPaintingEnabled()) {
     mRootViewManager->CallDidPaintOnObserver();
   }
 }
 
 nsresult nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsIView* aView, nsEventStatus* aStatus)
 {
   SAMPLE_LABEL("event", "nsViewManager::DispatchEvent");
@@ -1197,18 +1200,17 @@ nsViewManager::ProcessPendingUpdates()
   if (!IsRootVM()) {
     RootViewManager()->ProcessPendingUpdates();
     return;
   }
 
   if (IsRefreshDriverPaintingEnabled()) {
     mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
       
-    // Flush things like reflows and plugin widget geometry updates by
-    // calling WillPaint on observer presShells.
+    // Flush things like reflows by calling WillPaint on observer presShells.
     if (mPresShell) {
       CallWillPaintOnObservers(true);
     }
     ProcessPendingUpdatesForView(mRootView, true);
     CallDidPaintOnObserver();
   } else {
     ProcessPendingUpdatesForView(mRootView, true);
   }