Bug 721294. Only call nsIPresShell::WillPaint for the root presshell. Pass aWilLSendDidPaint correctly to nsIPresShell::Paint. Remove aPaintDefaultBackground from nsIPresShell::Paint. r=mats
authorRobert O'Callahan <robert@ocallahan.org>
Sat, 28 Jan 2012 16:36:23 +1300
changeset 86869 06d02e7132b28cd0aea416a772c444485ae34260
parent 86868 8f3fbc4a9c2a3971c1dcec4c7638e130ff6d027a
child 86870 eb80ab6ee07b7316fe51227659fa4158221bd17d
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs721294
milestone12.0a1
Bug 721294. Only call nsIPresShell::WillPaint for the root presshell. Pass aWilLSendDidPaint correctly to nsIPresShell::Paint. Remove aPaintDefaultBackground from nsIPresShell::Paint. r=mats
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
view/src/nsViewManager.cpp
view/src/nsViewManager.h
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -138,18 +138,18 @@ typedef struct CapturingContentInfo {
   // capture should only be allowed during a mousedown event
   bool mAllowed;
   bool mRetargetToElement;
   bool mPreventDrag;
   nsIContent* mContent;
 } CapturingContentInfo;
 
 #define NS_IPRESSHELL_IID    \
-{ 0x3ab5b116, 0x2d73, 0x431c, \
- { 0x9a, 0x4b, 0x6c, 0x91, 0x9e, 0x42, 0x45, 0xc3 } }
+        { 0x87acd089, 0x8da7, 0x4438, \
+          { 0xa5, 0xcd, 0x90, 0x1e, 0x5d, 0x8f, 0xd8, 0x19 } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
 #define NS_PRESSHELL_SCROLL_BOTTOM   100
 #define NS_PRESSHELL_SCROLL_LEFT     0
 #define NS_PRESSHELL_SCROLL_RIGHT    100
 #define NS_PRESSHELL_SCROLL_CENTER   50
 #define NS_PRESSHELL_SCROLL_ANYWHERE -1
@@ -1140,23 +1140,31 @@ public:
    * Dispatch a mouse move event based on the most recent mouse position if
    * this PresShell is visible. This is used when the contents of the page
    * moved (aFromScroll is false) or scrolled (aFromScroll is true).
    */
   virtual void SynthesizeMouseMove(bool aFromScroll) = 0;
 
   virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
                      const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
-                     bool aPaintDefaultBackground, bool aWillSendDidPaint) = 0;
+                     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.
+   */
   virtual void WillPaint(bool aWillSendDidPaint) = 0;
+  /**
+   * Notify that the NS_DID_PAINT event was received. Only fires on the
+   * root pres shell.
+   */
   virtual void DidPaint() = 0;
   virtual void ScheduleViewManagerFlush() = 0;
   virtual void ClearMouseCaptureOnView(nsIView* aView) = 0;
   virtual bool IsVisible() = 0;
   virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0;
 
   /**
    * Refresh observer management.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5422,17 +5422,16 @@ PresShell::ProcessSynthMouseMoveEvent(bo
   }
 }
 
 void
 PresShell::Paint(nsIView*           aViewToPaint,
                  nsIWidget*         aWidgetToPaint,
                  const nsRegion&    aDirtyRegion,
                  const nsIntRegion& aIntDirtyRegion,
-                 bool               aPaintDefaultBackground,
                  bool               aWillSendDidPaint)
 {
 #ifdef NS_FUNCTION_TIMER
   NS_TIME_FUNCTION_DECLARE_DOCURL;
   const nsRect& bounds__ = aDirtyRegion.GetBounds();
   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, dirty rect: (<%f, %f>, <%f, %f>)",
                            MOZ_FUNCTION_NAME, __LINE__, docURL__.get(),
                            NSCoordToFloat(bounds__.x),
@@ -5444,17 +5443,17 @@ PresShell::Paint(nsIView*           aVie
   SAMPLE_LABEL("Paint", "PresShell::Paint");
   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
   NS_ASSERTION(aViewToPaint, "null view");
   NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
 
   nsPresContext* presContext = GetPresContext();
   AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
 
-  nsIFrame* frame = aPaintDefaultBackground ? nsnull : aViewToPaint->GetFrame();
+  nsIFrame* frame = aViewToPaint->GetFrame();
 
   bool isRetainingManager;
   LayerManager* layerManager =
     aWidgetToPaint->GetLayerManager(&isRetainingManager);
   NS_ASSERTION(layerManager, "Must be in paint event");
   layerManager->BeginTransaction();
 
   if (frame && isRetainingManager) {
@@ -5483,19 +5482,16 @@ PresShell::Paint(nsIView*           aVie
   if (frame) {
     // Defer invalidates that are triggered during painting, and discard
     // invalidates of areas that are already being repainted.
     // The layer system can trigger invalidates during painting
     // (see FrameLayerBuilder).
     frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
 
     // We can paint directly into the widget using its layer manager.
-    // When we get rid of child widgets, this will be the only path we
-    // need. (aPaintDefaultBackground will never be needed since the
-    // chrome can always paint a default background.)
     nsLayoutUtils::PaintFrame(nsnull, frame, aDirtyRegion, bgcolor,
                               nsLayoutUtils::PAINT_WIDGET_LAYERS |
                               nsLayoutUtils::PAINT_EXISTING_TRANSACTION);
 
     frame->EndDeferringInvalidatesForDisplayRoot();
     presContext->NotifyDidPaintForSubtree();
     return;
   }
@@ -7203,20 +7199,21 @@ PresShell::WillPaint(bool aWillSendDidPa
 
 void
 PresShell::DidPaint()
 {
   if (mPaintingSuppressed || !mIsActive || !IsVisible()) {
     return;
   }
 
+  NS_ASSERTION(mPresContext->IsRoot(), "Should only call DidPaint on root presshells");
+
   nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext();
-  if (!rootPresContext) {
-    return;
-  }
+  // 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->UpdatePluginGeometry();
   }
 }
 
 bool
 PresShell::IsVisible()
 {
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -311,17 +311,17 @@ public:
   virtual void SetDisplayPort(const nsRect& aDisplayPort);
 
   virtual nsresult SetResolution(float aXResolution, float aYResolution);
 
   //nsIViewObserver interface
 
   virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
                      const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
-                     bool aPaintDefaultBackground, bool aWillSendDidPaint);
+                     bool aWillSendDidPaint);
   virtual nsresult HandleEvent(nsIFrame*       aFrame,
                                nsGUIEvent*     aEvent,
                                bool            aDontRetargetEvents,
                                nsEventStatus*  aEventStatus);
   virtual NS_HIDDEN_(nsresult) HandleDOMEventWithTarget(nsIContent* aTargetContent,
                                                         nsEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual NS_HIDDEN_(nsresult) HandleDOMEventWithTarget(nsIContent* aTargetContent,
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -332,17 +332,18 @@ nsIView* nsIViewManager::GetDisplayRootF
 }
 
 /**
    aRegion is given in device coordinates!!
    aContext may be null, in which case layers should be used for
    rendering.
 */
 void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
-                            const nsIntRegion& aRegion)
+                            const nsIntRegion& aRegion,
+                            bool aWillSendDidPaint)
 {
   NS_ASSERTION(aView == nsView::GetViewFor(aWidget), "view widget mismatch");
   NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
 
   // damageRegion is the damaged area, in twips, relative to the view origin
   nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
   // move region from widget coordinates into view coordinates
   damageRegion.MoveBy(-aView->ViewToWidgetOffset());
@@ -363,44 +364,34 @@ void nsViewManager::Refresh(nsView *aVie
     RootViewManager()->mRecursiveRefreshPending = true;
     return;
   }  
 
   {
     nsAutoScriptBlocker scriptBlocker;
     SetPainting(true);
 
-    RenderViews(aView, aWidget, damageRegion, aRegion, false, false);
+    NS_ASSERTION(GetDisplayRootFor(aView) == aView,
+                 "Widgets that we paint must all be display roots");
+
+    if (mPresShell) {
+      mPresShell->Paint(aView, aWidget, damageRegion, aRegion,
+                        aWillSendDidPaint);
+      mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
+    }
 
     SetPainting(false);
   }
 
   if (RootViewManager()->mRecursiveRefreshPending) {
     RootViewManager()->mRecursiveRefreshPending = false;
     InvalidateAllViews();
   }
 }
 
-// aRC and aRegion are in view coordinates
-void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget,
-                                const nsRegion& aRegion,
-                                const nsIntRegion& aIntRegion,
-                                bool aPaintDefaultBackground,
-                                bool aWillSendDidPaint)
-{
-  NS_ASSERTION(GetDisplayRootFor(aView) == aView,
-               "Widgets that we paint must all be display roots");
-
-  if (mPresShell) {
-    mPresShell->Paint(aView, aWidget, aRegion, aIntRegion,
-                      aPaintDefaultBackground, aWillSendDidPaint);
-    mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
-  }
-}
-
 void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
                                                  bool aFlushDirtyRegion)
 {
   NS_ASSERTION(IsRootVM(), "Updates will be missed");
 
   // Protect against a null-view.
   if (!aView) {
     return;
@@ -814,24 +805,24 @@ NS_IMETHODIMP nsViewManager::DispatchEve
           // destroyed it during CallWillPaintOnObservers (bug 378273).
           view = nsView::GetViewFor(event->widget);
         }
 
         if (!view || event->region.IsEmpty())
           break;
 
         // Paint.
-        Refresh(view, event->widget, event->region);
+        Refresh(view, event->widget, event->region, event->willSendDidPaint);
 
         break;
       }
 
     case NS_DID_PAINT: {
       nsRefPtr<nsViewManager> rootVM = RootViewManager();
-      rootVM->CallDidPaintOnObservers();
+      rootVM->CallDidPaintOnObserver();
       break;
     }
 
     case NS_CREATE:
     case NS_DESTROY:
     case NS_SETZLEVEL:
       /* Don't pass these events through. Passing them through
          causes performance problems on pages with lots of views/frames 
@@ -1392,31 +1383,24 @@ nsViewManager::CallWillPaintOnObservers(
           shell->WillPaint(aWillSendDidPaint);
         }
       }
     }
   }
 }
 
 void
-nsViewManager::CallDidPaintOnObservers()
+nsViewManager::CallDidPaintOnObserver()
 {
   NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
 
-  PRInt32 index;
-  for (index = 0; index < mVMCount; index++) {
-    nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index);
-    if (vm->RootViewManager() == this) {
-      // One of our kids.
-      if (vm->mRootView && vm->mRootView->IsEffectivelyVisible()) {
-        nsCOMPtr<nsIPresShell> shell = vm->GetPresShell();
-        if (shell) {
-          shell->DidPaint();
-        }
-      }
+  if (mRootView && mRootView->IsEffectivelyVisible()) {
+    nsCOMPtr<nsIPresShell> shell = GetPresShell();
+    if (shell) {
+      shell->DidPaint();
     }
   }
 }
 
 NS_IMETHODIMP
 nsViewManager::GetLastUserEventTime(PRUint32& aTime)
 {
   aTime = gLastUserEventTime;
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -148,30 +148,26 @@ private:
   void FlushPendingInvalidates();
   void ProcessPendingUpdatesForView(nsView *aView,
                                     bool aFlushDirtyRegion = true);
   void FlushDirtyRegionToWidget(nsView* aView);
   /**
    * Call WillPaint() on all view observers under this vm root.
    */
   void CallWillPaintOnObservers(bool aWillSendDidPaint);
-  void CallDidPaintOnObservers();
+  void CallDidPaintOnObserver();
   void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
   void ReparentWidgets(nsIView* aView, nsIView *aParent);
   void InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion);
 
   void InvalidateViews(nsView *aView);
 
   // aView is the view for aWidget and aRegion is relative to aWidget.
-  void Refresh(nsView *aView, nsIWidget *aWidget, const nsIntRegion& aRegion);
-  // aRootView is the view for aWidget, aRegion is relative to aRootView, and
-  // aIntRegion is relative to aWidget.
-  void RenderViews(nsView *aRootView, nsIWidget *aWidget,
-                   const nsRegion& aRegion, const nsIntRegion& aIntRegion,
-                   bool aPaintDefaultBackground, bool aWillSendDidPaint);
+  void Refresh(nsView *aView, nsIWidget *aWidget, const nsIntRegion& aRegion,
+               bool aWillSendDidPaint);
 
   void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut);
   void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
                                           nscoord aY1, nscoord aY2, bool aInCutOut);
 
   // Utilities
 
   bool IsViewInserted(nsView *aView);