Bug 598482 part 11 - Set up a connection between the view manager and the refresh driver. r=roc
authorMarkus Stange <mstange@themasta.com>
Fri, 23 Dec 2011 22:52:22 -0500
changeset 84539 fc0f7ad1de41d5d32821c82b1e8c723931ce14f3
parent 84538 42fde5b5e0982248010433d2d565974bd2949015
child 84540 84a70e2a270e659ccc4e97037be8329574ae91d1
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)
reviewersroc
bugs598482
milestone12.0a1
Bug 598482 part 11 - Set up a connection between the view manager and the refresh driver. r=roc
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
view/public/nsIViewManager.h
view/src/nsViewManager.cpp
view/src/nsViewManager.h
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -136,18 +136,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    \
-{ 0x4e23d557, 0x741a, 0x4fd0,\
-  { 0x91, 0x52, 0x34, 0xe2, 0xb4, 0xef, 0xe8, 0x2e } }
+{ 0x3ab5b116, 0x2d73, 0x431c, \
+ { 0x9a, 0x4b, 0x6c, 0x91, 0x9e, 0x42, 0x45, 0xc3 } }
 
 // 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
@@ -1143,16 +1143,17 @@ public:
                      bool aPaintDefaultBackground, bool aWillSendDidPaint) = 0;
   virtual nsresult HandleEvent(nsIFrame*       aFrame,
                                nsGUIEvent*     aEvent,
                                bool            aDontRetargetEvents,
                                nsEventStatus*  aEventStatus) = 0;
   virtual bool ShouldIgnoreInvalidation() = 0;
   virtual void WillPaint(bool aWillSendDidPaint) = 0;
   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.
    */
 protected:
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1263,16 +1263,18 @@ PresShell::Destroy()
       mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd);
     }
   }
 
   // Revoke any pending events.  We need to do this and cancel pending reflows
   // before we destroy the frame manager, since apparently frame destruction
   // sometimes spins the event queue when plug-ins are involved(!).
   rd->RemoveLayoutFlushObserver(this);
+  rd->RevokeViewManagerFlush();
+
   mResizeEvent.Revoke();
   if (mAsyncResizeTimerIsActive) {
     mAsyncResizeEventTimer->Cancel();
     mAsyncResizeTimerIsActive = false;
   }
 
   CancelAllPendingReflows();
   CancelPostedReflowCallbacks();
@@ -3621,16 +3623,25 @@ nsresult PresShell::GetLinkLocation(nsID
     }
   }
 
   // if no link, fail.
   return NS_ERROR_FAILURE;
 }
 
 void
+PresShell::ScheduleViewManagerFlush()
+{
+  nsPresContext* presContext = GetPresContext();
+  if (presContext) {
+    presContext->RefreshDriver()->ScheduleViewManagerFlush();
+  }
+}
+
+void
 PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent,
                                   bool aFlushOnHoverChange)
 {
   PRUint32 hoverGenerationBefore = mFrameConstructor->GetHoverGeneration();
   nsEventStatus status;
   nsIView* targetView = nsIView::GetViewFor(aEvent->widget);
   targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
   if (aFlushOnHoverChange &&
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -325,16 +325,17 @@ 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 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();
   NS_IMETHOD SetCaretEnabled(bool aInEnable);
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -50,16 +50,17 @@
 #include "nsAutoPtr.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsIDocument.h"
 #include "nsGUIEvent.h"
 #include "nsEventDispatcher.h"
 #include "jsapi.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
+#include "nsIViewManager.h"
 
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 
 using namespace mozilla;
 
 #define DEFAULT_FRAME_RATE 60
 #define DEFAULT_THROTTLED_FRAME_RATE 1
@@ -107,16 +108,17 @@ nsRefreshDriver::GetRefreshTimerType() c
 }
 
 nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext)
   : mPresContext(aPresContext),
     mFrozen(false),
     mThrottled(false),
     mTestControllingRefreshes(false),
     mTimerIsPrecise(false),
+    mViewManagerFlushIsPending(false),
     mLastTimerInterval(0)
 {
   mRequests.Init();
 }
 
 nsRefreshDriver::~nsRefreshDriver()
 {
   NS_ABORT_IF_FALSE(ObserverCount() == 0,
@@ -265,16 +267,17 @@ nsRefreshDriver::ObserverCount() const
 
   // Even while throttled, we need to process layout and style changes.  Style
   // changes can trigger transitions which fire events when they complete, and
   // layout changes can affect media queries on child documents, triggering
   // style changes, etc.
   sum += mStyleFlushObservers.Length();
   sum += mLayoutFlushObservers.Length();
   sum += mFrameRequestCallbackDocs.Length();
+  sum += mViewManagerFlushIsPending;
   return sum;
 }
 
 PRUint32
 nsRefreshDriver::ImageRequestCount() const
 {
   return mRequests.Count();
 }
@@ -426,16 +429,21 @@ nsRefreshDriver::Notify(nsITimer *aTimer
    */
 
   ImageRequestParameters parms = {mMostRecentRefresh};
   if (mRequests.Count()) {
     mRequests.EnumerateEntries(nsRefreshDriver::ImageRequestEnumerator, &parms);
     EnsureTimerStarted(false);
   }
 
+  if (mViewManagerFlushIsPending) {
+    mViewManagerFlushIsPending = false;
+    mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
+  }
+
   if (mThrottled ||
       (mTimerIsPrecise !=
        (GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) {
     // Stop the timer now and restart it here.  Stopping is in the mThrottled
     // case ok because either it's already one-shot, and it just fired, and all
     // we need to do is null it out, or it's repeating and we need to reset it
     // to be one-shot.  Stopping and restarting in the case when we need to
     // switch from precise to slack timers or vice versa is unfortunately
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -172,16 +172,27 @@ public:
   void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
     mLayoutFlushObservers.RemoveElement(aShell);
   }
   bool IsLayoutFlushObserver(nsIPresShell* aShell) {
     return mLayoutFlushObservers.Contains(aShell);
   }
 
   /**
+   * Remember whether our presshell's view manager needs a flush
+   */
+  void ScheduleViewManagerFlush() {
+    mViewManagerFlushIsPending = true;
+    EnsureTimerStarted(false);
+  }
+  void RevokeViewManagerFlush() {
+    mViewManagerFlushIsPending = false;
+  }
+
+  /**
    * Add a document for which we have nsIFrameRequestCallbacks
    */
   void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
    * Remove a document for which we have nsIFrameRequestCallbacks
    */
   void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
@@ -260,16 +271,17 @@ private:
 
   bool mFrozen;
   bool mThrottled;
   bool mTestControllingRefreshes;
   /* If mTimer is non-null, this boolean indicates whether the timer is
      a precise timer.  If mTimer is null, this boolean's value can be
      anything.  */
   bool mTimerIsPrecise;
+  bool mViewManagerFlushIsPending;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];
   RequestTable mRequests;
 
   nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
   // nsTArray on purpose, because we want to be able to swap.
--- a/view/public/nsIViewManager.h
+++ b/view/public/nsIViewManager.h
@@ -343,13 +343,19 @@ public:
    */
   NS_IMETHOD GetLastUserEventTime(PRUint32& aTime)=0;
 
   /**
    * Find the nearest display root view for the view aView. This is the view for
    * the nearest enclosing popup or the root view for the root document.
    */
   static nsIView* GetDisplayRootFor(nsIView* aView);
+
+  /**
+   * Flush the accumulated dirty region to the widget and update widget
+   * geometry.
+   */
+  virtual void ProcessPendingUpdates()=0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewManager, NS_IVIEWMANAGER_IID)
 
 #endif  // nsIViewManager_h___
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -393,33 +393,34 @@ void nsViewManager::RenderViews(nsView *
 
   if (mPresShell) {
     mPresShell->Paint(aView, aWidget, aRegion, aIntRegion,
                       aPaintDefaultBackground, aWillSendDidPaint);
     mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
   }
 }
 
-void nsViewManager::ProcessPendingUpdates(nsView* aView, bool aDoInvalidate)
+void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
+                                                 bool aDoInvalidate)
 {
   NS_ASSERTION(IsRootVM(), "Updates will be missed");
 
   // Protect against a null-view.
   if (!aView) {
     return;
   }
 
   if (aView->HasWidget()) {
     aView->ResetWidgetBounds(false, false, true);
   }
 
   // process pending updates in child view.
   for (nsView* childView = aView->GetFirstChild(); childView;
        childView = childView->GetNextSibling()) {
-    ProcessPendingUpdates(childView, aDoInvalidate);
+    ProcessPendingUpdatesForView(childView, aDoInvalidate);
   }
 
   if (aDoInvalidate) {
     // Push out updates after we've processed the children; ensures that
     // damage is applied based on the final widget geometry
     NS_ASSERTION(IsRefreshEnabled(), "Cannot process pending updates with refresh disabled");
     FlushDirtyRegionToWidget(aView);
   }
@@ -823,17 +824,17 @@ NS_IMETHODIMP nsViewManager::DispatchEve
                 // 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->ProcessPendingUpdates(mRootView, false);
+              rootVM->ProcessPendingUpdatesForView(mRootView, false);
             }
             
             if (view && aEvent->message == NS_PAINT) {
               Refresh(view, event->widget, event->region);
             }
           }
         } else if (aEvent->message == NS_PAINT) {
           // since we got an NS_PAINT event, we need to
@@ -1420,23 +1421,29 @@ nsIntRect nsViewManager::ViewToWidget(ns
 NS_IMETHODIMP
 nsViewManager::IsPainting(bool& aIsPainting)
 {
   aIsPainting = IsPainting();
   return NS_OK;
 }
 
 void
+nsViewManager::ProcessPendingUpdates()
+{
+  // To be implemented.
+}
+
+void
 nsViewManager::FlushPendingInvalidates()
 {
   NS_ASSERTION(IsRootVM(), "Must be root VM for this to be called!");
   NS_ASSERTION(mUpdateBatchCnt == 0, "Must not be in an update batch!");
 
   if (mHasPendingUpdates) {
-    ProcessPendingUpdates(mRootView, true);
+    ProcessPendingUpdatesForView(mRootView, true);
     mHasPendingUpdates = false;
   }
 }
 
 void
 nsViewManager::CallWillPaintOnObservers(bool aWillSendDidPaint)
 {
   NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -139,23 +139,25 @@ public:
  
   NS_IMETHOD IsPainting(bool& aIsPainting);
   NS_IMETHOD GetLastUserEventTime(PRUint32& aTime);
   static PRUint32 gLastUserEventTime;
 
   /* Update the cached RootViewManager pointer on this view manager. */
   void InvalidateHierarchy();
 
+  virtual void ProcessPendingUpdates();
+
 protected:
   virtual ~nsViewManager();
 
 private:
 
   void FlushPendingInvalidates();
-  void ProcessPendingUpdates(nsView *aView, bool aDoInvalidate);
+  void ProcessPendingUpdatesForView(nsView *aView, bool aDoInvalidate);
   void FlushDirtyRegionToWidget(nsView* aView);
   /**
    * Call WillPaint() on all view observers under this vm root.
    */
   void CallWillPaintOnObservers(bool aWillSendDidPaint);
   void CallDidPaintOnObservers();
   void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
   void ReparentWidgets(nsIView* aView, nsIView *aParent);