bug 627628 - Throttle the dispatching of starved paints so that time is allowed for the processing of input events between each starved paint. r=roc
authorKevin Gadd <kevin.gadd@gmail.com>
Fri, 13 Jan 2012 19:29:22 -0600
changeset 85660 f4d1511c16ba1821a72aa124988e1231758e9635
parent 85659 b36175bbda47da731573c8031a132a4f2385235d
child 85661 4dd329d75054a9d949f5b26197425ea3520888f3
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
bugs627628
milestone12.0a1
bug 627628 - Throttle the dispatching of starved paints so that time is allowed for the processing of input events between each starved paint. r=roc This helps maintain responsiveness in cases where input events are being generated very rapidly or where painting is extremely expensive.
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
widget/windows/nsWindowGfx.cpp
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3752,19 +3752,21 @@ void nsWindow::DispatchPendingEvents()
   // At the same time, we don't want to recurse through here
   // as that would prevent us from dispatching starved paints.
   static int recursionBlocker = 0;
   if (recursionBlocker++ == 0) {
     NS_ProcessPendingEvents(nsnull, PR_MillisecondsToInterval(100));
     --recursionBlocker;
   }
 
-  // Quickly check to see if there are any
-  // paint events pending.
-  if (::GetQueueStatus(QS_PAINT)) {
+  // Quickly check to see if there are any paint events pending,
+  // but only dispatch them if it has been long enough since the
+  // last paint completed.
+  if (::GetQueueStatus(QS_PAINT) &&
+      ((TimeStamp::Now() - mLastPaintEndTime).ToMilliseconds() >= 50)) {
     // Find the top level window.
     HWND topWnd = WinUtils::GetTopLevelHWND(mWnd);
 
     // Dispatch pending paints for topWnd and all its descendant windows.
     // Note: EnumChildWindows enumerates all descendant windows not just
     // the children (but not the window itself).
     nsWindow::DispatchStarvedPaints(topWnd, 0);
     ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0);
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -56,16 +56,18 @@
 #include "nsIdleService.h"
 #include "nsToolkit.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "gfxWindowsSurface.h"
 #include "nsWindowDbg.h"
 #include "cairo.h"
 #include "nsITimer.h"
+#include "mozilla/TimeStamp.h"
+
 #ifdef CAIRO_HAS_D2D_SURFACE
 #include "gfxD2DSurface.h"
 #endif
 
 #include "nsWinGesture.h"
 
 #include "WindowHook.h"
 #include "TaskbarWindowPreview.h"
@@ -89,16 +91,18 @@ class nsIFile;
 class imgIContainer;
 
 /**
  * Native WIN32 window wrapper.
  */
 
 class nsWindow : public nsBaseWidget
 {
+  typedef mozilla::TimeStamp TimeStamp;
+  typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::widget::WindowHook WindowHook;
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
   typedef mozilla::widget::TaskbarWindowPreview TaskbarWindowPreview;
 #endif
 public:
   nsWindow();
   virtual ~nsWindow();
 
@@ -606,16 +610,20 @@ protected:
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
   // Weak ref to the nsITaskbarWindowPreview associated with this window
   nsWeakPtr             mTaskbarPreview;
   // True if the taskbar (possibly through the tab preview) tells us that the
   // icon has been created on the taskbar.
   bool                  mHasTaskbarIconBeenCreated;
 #endif
 
+  // The point in time at which the last paint completed. We use this to avoid
+  //  painting too rapidly in response to frequent input events.
+  TimeStamp mLastPaintEndTime;
+
 #ifdef ACCESSIBILITY
   static BOOL           sIsAccessibilityOn;
   static HINSTANCE      sAccLib;
   static LPFNLRESULTFROMOBJECT sLresultFromObject;
 #endif // ACCESSIBILITY
 
   // sRedirectedKeyDown is WM_KEYDOWN message or WM_SYSKEYDOWN message which
   // was reirected to SendInput() API by OnKeyDown().
--- a/widget/windows/nsWindowGfx.cpp
+++ b/widget/windows/nsWindowGfx.cpp
@@ -600,16 +600,17 @@ bool nsWindow::OnPaint(HDC aDC, PRUint32
     }
   }
 
   if (!aDC) {
     ::EndPaint(mWnd, &ps);
   }
 
   mPaintDC = nsnull;
+  mLastPaintEndTime = TimeStamp::Now();
 
 #if defined(WIDGET_DEBUG_OUTPUT)
   if (debug_WantPaintFlashing())
   {
     // Only flash paint events which have not ignored the paint message.
     // Those that ignore the paint message aren't painting anything so there
     // is only the overhead of the dispatching the paint event.
     if (nsEventStatus_eIgnore != eventStatus) {