Backout Bug 930793 - Remove favor performance mode (we have still racy b2g tests), a=backout
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Thu, 30 Jan 2014 21:35:44 -0800
changeset 182190 89f9304ff4baf44fa4893998dae116e6746d8783
parent 182189 1bb4238bdde3285e412492b8687da1e7ee5a36e7
child 182191 2a7a697f2d88da4b1290c555c09f5259031c99e0
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs930793
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout Bug 930793 - Remove favor performance mode (we have still racy b2g tests), a=backout
content/base/src/nsContentSink.cpp
content/base/src/nsContentSink.h
docshell/base/nsDocShell.cpp
dom/tests/mochitest/general/test_vibrator.html
dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
layout/base/nsRefreshDriver.cpp
view/public/nsViewManager.h
view/src/nsViewManager.cpp
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/nsIAppShell.idl
widget/nsIWidget.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
widget/windows/winrt/MetroWidget.cpp
widget/windows/winrt/MetroWidget.h
widget/xpwidgets/nsBaseAppShell.cpp
widget/xpwidgets/nsBaseAppShell.h
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -195,16 +195,17 @@ nsContentSink::Init(nsIDocument* aDoc,
   mCSSLoader = aDoc->CSSLoader();
 
   mNodeInfoManager = aDoc->NodeInfoManager();
 
   mBackoffCount = sBackoffCount;
 
   if (sEnablePerfMode != 0) {
     mDynamicLowerValue = sEnablePerfMode == 1;
+    FavorPerformanceHint(!mDynamicLowerValue, 0);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
                                 bool aWasAlternate,
@@ -1371,16 +1372,25 @@ nsContentSink::DidProcessATokenImpl()
   }
 
   return NS_OK;
 }
 
 //----------------------------------------------------------------------
 
 void
+nsContentSink::FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay)
+{
+  static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
+  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
+  if (appShell)
+    appShell->FavorPerformanceHint(perfOverStarvation, starvationDelay);
+}
+
+void
 nsContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType)
 {
   // Remember nested updates from updates that we started.
   if (mInNotification > 0 && mUpdatesInNotification < 2) {
     ++mUpdatesInNotification;
   }
 
   // If we're in a script and we didn't do the notification,
@@ -1447,16 +1457,22 @@ nsContentSink::DropParserAndPerfHint(voi
   // Do this hack to make sure that the parser
   // doesn't get destroyed, accidently, before
   // the circularity, between sink & parser, is
   // actually broken.
   // Drop our reference to the parser to get rid of a circular
   // reference.
   nsRefPtr<nsParserBase> kungFuDeathGrip(mParser.forget());
 
+  if (mDynamicLowerValue) {
+    // Reset the performance hint which was set to FALSE
+    // when mDynamicLowerValue was set.
+    FavorPerformanceHint(true, 0);
+  }
+
   if (!mRunsToCompletion) {
     mDocument->UnblockOnload(true);
   }
 }
 
 bool
 nsContentSink::IsScriptExecutingImpl()
 {
@@ -1484,16 +1500,17 @@ nsContentSink::WillParseImpl(void)
     vm->GetLastUserEventTime(lastEventTime);
 
     bool newDynLower =
       mDocument->IsInBackgroundWindow() ||
       ((currentTime - mBeginLoadTime) > uint32_t(sInitialPerfTime) &&
        (currentTime - lastEventTime) < uint32_t(sInteractiveTime));
     
     if (mDynamicLowerValue != newDynLower) {
+      FavorPerformanceHint(!newDynLower, 0);
       mDynamicLowerValue = newDynLower;
     }
   }
   
   mDeflectedCount = 0;
   mHasPendingEvent = false;
 
   mCurrentParseEndTime = currentTime +
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -232,16 +232,19 @@ protected:
   // we still have stylesheet loads pending.  Otherwise, we'll wait until the
   // stylesheets are all done loading.
 public:
   void StartLayout(bool aIgnorePendingSheets);
 
   static void NotifyDocElementCreated(nsIDocument* aDoc);
 
 protected:
+  void
+  FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay);
+
   inline int32_t GetNotificationInterval()
   {
     if (mDynamicLowerValue) {
       return 1000;
     }
 
     return sNotificationInterval;
   }
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -206,16 +206,19 @@ static NS_DEFINE_CID(kAppShellCID, NS_AP
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // True means sUseErrorPages has been added to preferences var cache.
 static bool gAddedPreferencesVarCache = false;
 
 bool nsDocShell::sUseErrorPages = false;
 
+// Number of documents currently loading
+static int32_t gNumberOfDocumentsLoading = 0;
+
 // Global count of existing docshells.
 static int32_t gDocShellCount = 0;
 
 // Global count of docshells with the private attribute set
 static uint32_t gNumberOfPrivateDocShells = 0;
 
 // Global reference to the URI fixup service.
 nsIURIFixup *nsDocShell::sURIFixup = 0;
@@ -236,16 +239,27 @@ static uint32_t gValidateOrigin = 0xffff
 static PRLogModuleInfo* gDocShellLog;
 #endif
 static PRLogModuleInfo* gDocShellLeakLog;
 #endif
 
 const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
 const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
 
+static void
+FavorPerformanceHint(bool perfOverStarvation)
+{
+    nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
+    if (appShell) {
+        appShell->FavorPerformanceHint(perfOverStarvation,
+                                       Preferences::GetUint("docshell.event_starvation_delay_hint",
+                                                            NS_EVENT_STARVATION_DELAY_HINT));
+    }
+}
+
 //*****************************************************************************
 // <a ping> support
 //*****************************************************************************
 
 #define PREF_PINGS_ENABLED           "browser.send_pings"
 #define PREF_PINGS_MAX_PER_LINK      "browser.send_pings.max_per_link"
 #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
 
@@ -6847,16 +6861,24 @@ nsDocShell::EndPageLoad(nsIWebProgress *
     // Notify the ContentViewer that the Document has finished loading.  This
     // will cause any OnLoad(...) and PopState(...) handlers to fire.
     if (!mEODForCurrentDocument && mContentViewer) {
         mIsExecutingOnLoadHandler = true;
         mContentViewer->LoadComplete(aStatus);
         mIsExecutingOnLoadHandler = false;
 
         mEODForCurrentDocument = true;
+
+        // If all documents have completed their loading
+        // favor native event dispatch priorities
+        // over performance
+        if (--gNumberOfDocumentsLoading == 0) {
+          // Hint to use normal native event dispatch priorities 
+          FavorPerformanceHint(false);
+        }
     }
     /* Check if the httpChannel has any cache-control related response headers,
      * like no-store, no-cache. If so, update SHEntry so that 
      * when a user goes back/forward to this page, we appropriately do 
      * form value restoration or load from server.
      */
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
     if (!httpChannel) // HttpChannel could be hiding underneath a Multipart channel.    
@@ -7850,16 +7872,22 @@ nsDocShell::RestoreFromHistory()
     // but we don't want them to stay around in case the page is reloaded.
     SetLayoutHistoryState(nullptr);
 
     // This is the end of our Embed() replacement
 
     mSavingOldViewer = false;
     mEODForCurrentDocument = false;
 
+    // Tell the event loop to favor plevents over user events, see comments
+    // in CreateContentViewer.
+    if (++gNumberOfDocumentsLoading == 1)
+        FavorPerformanceHint(true);
+
+
     if (oldMUDV && newMUDV) {
         newMUDV->SetMinFontSize(minFontSize);
         newMUDV->SetTextZoom(textZoom);
         newMUDV->SetFullZoom(pageZoom);
         newMUDV->SetAuthorStyleDisabled(styleDisabled);
     }
 
     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
@@ -8246,16 +8274,26 @@ nsDocShell::CreateContentViewer(const ch
         if (doc) {
           uint32_t partID;
           multiPartChannel->GetPartID(&partID);
           doc->SetPartID(partID);
         }
       }
     }
 
+    // Give hint to native plevent dispatch mechanism. If a document
+    // is loading the native plevent dispatch mechanism should favor
+    // performance over normal native event dispatch priorities.
+    if (++gNumberOfDocumentsLoading == 1) {
+      // Hint to favor performance for the plevent notification mechanism.
+      // We want the pages to load as fast as possible even if its means 
+      // native messages might be starved.
+      FavorPerformanceHint(true);
+    }
+
     if (onLocationChangeNeeded) {
       FireOnLocationChange(this, request, mCurrentURI, 0);
     }
   
     return NS_OK;
 }
 
 nsresult
--- a/dom/tests/mochitest/general/test_vibrator.html
+++ b/dom/tests/mochitest/general/test_vibrator.html
@@ -52,17 +52,17 @@ function testSuccesses() {
   expectSuccess(1000);
   expectSuccess(1000.1);
   expectSuccess([0, 0, 0]);
   expectSuccess(['1000', 1000]);
   expectSuccess([1000, 1000]);
   expectSuccess([1000, 1000.1]);
 
   // The following loop shouldn't cause us to crash.  See bug 701716.
-  for (var i = 0; i < 1000; i++) {
+  for (var i = 0; i < 10000; i++) {
     navigator.vibrate([100, 100]);
   }
   ok(true, "Didn't crash after issuing a lot of vibrate() calls.");
 }
 
 var origVibratorEnabled = SpecialPowers.getBoolPref('dom.vibrator.enabled');
 
 // Test with the vibrator pref enabled.
--- a/dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
+++ b/dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
@@ -46,19 +46,19 @@ https://bugzilla.mozilla.org/show_bug.cg
         is(unLockedCoords.screenY, lockedCoords.screenY,
            "screenY should be equal to where the mouse was originaly locked");
       }
 
       function moveUnlocked(e) {
         var firstCall = !unLockedCoords;
         if (!firstCall) {
           todo(false, "mousemove is fired twice.");
-        } else {
-          isUnlocked = !document.mozPointerLockElement;
         }
+
+        isUnlocked = !document.mozPointerLockElement;
         unLockedCoords = {
           screenX: e.screenX,
           screenY: e.screenY,
           clientX: e.clientX,
           clientY: e.clientY
         };
 
         if (!firstCall) {
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1199,17 +1199,17 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
 #ifdef MOZ_DUMP_PAINTING
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
       printf_stderr("Starting ProcessPendingUpdates\n");
     }
 #endif
 
     mViewManagerFlushIsPending = false;
     nsRefPtr<nsViewManager> vm = mPresContext->GetPresShell()->GetViewManager();
-    vm->ProcessPendingUpdates(nsViewManager::eTrySyncUpdate);
+    vm->ProcessPendingUpdates();
 #ifdef MOZ_DUMP_PAINTING
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
       printf_stderr("Ending ProcessPendingUpdates\n");
     }
 #endif
   }
 
   for (uint32_t i = 0; i < mPostRefreshObservers.Length(); ++i) {
--- a/view/public/nsViewManager.h
+++ b/view/public/nsViewManager.h
@@ -297,26 +297,21 @@ public:
   void GetLastUserEventTime(uint32_t& aTime);
 
   /**
    * 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 nsView* GetDisplayRootFor(nsView* aView);
 
-  enum UpdatingMode {
-    eNoSyncUpdate,
-    eTrySyncUpdate
-  };
-
   /**
    * Flush the accumulated dirty region to the widget and update widget
    * geometry.
    */
-  void ProcessPendingUpdates(UpdatingMode aMode);
+  void ProcessPendingUpdates();
 
   /**
    * Just update widget geometry without flushing the dirty region
    */
   void UpdateWidgetGeometry();
 
   int32_t AppUnitsPerDevPixel() const
   {
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -649,17 +649,17 @@ void nsViewManager::InvalidateViews(nsVi
 
 void nsViewManager::WillPaintWindow(nsIWidget* aWidget)
 {
   if (aWidget) {
     nsView* view = nsView::GetViewFor(aWidget);
     LayerManager *manager = aWidget->GetLayerManager();
     if (view &&
         (view->ForcedRepaint() || !manager->NeedsWidgetInvalidation())) {
-      ProcessPendingUpdates(eNoSyncUpdate);
+      ProcessPendingUpdates();
       // Re-get the view pointer here since the ProcessPendingUpdates might have
       // destroyed it during CallWillPaintOnObservers.
       view = nsView::GetViewFor(aWidget);
       if (view) {
         view->SetForcedRepaint(false);
       }
     }
   }
@@ -1032,38 +1032,30 @@ nsIntRect nsViewManager::ViewToWidget(ns
 
 void
 nsViewManager::IsPainting(bool& aIsPainting)
 {
   aIsPainting = IsPainting();
 }
 
 void
-nsViewManager::ProcessPendingUpdates(UpdatingMode aMode)
+nsViewManager::ProcessPendingUpdates()
 {
   if (!IsRootVM()) {
-    RootViewManager()->ProcessPendingUpdates(aMode);
+    RootViewManager()->ProcessPendingUpdates();
     return;
   }
 
   mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
 
   // Flush things like reflows by calling WillPaint on observer presShells.
   if (mPresShell) {
     CallWillPaintOnObservers();
   }
   ProcessPendingUpdatesForView(mRootView, true);
-
-  if (aMode == eTrySyncUpdate) {
-    nsCOMPtr<nsIWidget> w;
-    GetRootWidget(getter_AddRefs(w));
-    if (w) {
-      w->Update();
-    }
-  }
 }
 
 void
 nsViewManager::UpdateWidgetGeometry()
 {
   if (!IsRootVM()) {
     RootViewManager()->UpdateWidgetGeometry();
     return;
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -485,17 +485,16 @@ public:
   // between HiDPI and non-HiDPI screens
   void                    BackingScaleFactorChanged();
 
   virtual double          GetDefaultScaleInternal();
 
   virtual int32_t         RoundsWidgetCoordinatesTo() MOZ_OVERRIDE;
 
   NS_IMETHOD              Invalidate(const nsIntRect &aRect);
-  virtual void            Update() MOZ_OVERRIDE;
 
   virtual void*           GetNativeData(uint32_t aDataType);
   virtual nsresult        ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
   virtual nsIntPoint      WidgetToScreenOffset();
   virtual bool            ShowsResizeIndicator(nsIntRect* aResizerRect);
 
   static  bool            ConvertStatus(nsEventStatus aStatus)
                           { return aStatus == nsEventStatus_eConsumeNoDefault; }
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1576,28 +1576,16 @@ NS_IMETHODIMP nsChildView::Invalidate(co
     [mView setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)];
   }
 
   return NS_OK;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
 }
 
-void
-nsChildView::Update()
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
-
-  if (!ShouldUseOffMainThreadCompositing() && mView) {
-    [mView displayIfNeeded];
-  }
-
-  NS_OBJC_END_TRY_ABORT_BLOCK;
-}
-
 bool
 nsChildView::ComputeShouldAccelerate(bool aDefault)
 {
   // Don't use OpenGL for transparent windows or for popup windows.
   if (!mView || ![[mView window] isOpaque] ||
       [[mView window] isKindOfClass:[PopupWindow class]])
     return false;
 
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1612,24 +1612,16 @@ nsWindow::Invalidate(const nsIntRect &aR
     LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
              rect.x, rect.y, rect.width, rect.height));
 
     gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
 
     return NS_OK;
 }
 
-void
-nsWindow::Update()
-{
-    if (!ShouldUseOffMainThreadCompositing() && mGdkWindow) {
-        gdk_window_process_updates(mGdkWindow, true);
-    }
-}
-
 void*
 nsWindow::GetNativeData(uint32_t aDataType)
 {
     switch (aDataType) {
     case NS_NATIVE_WINDOW:
     case NS_NATIVE_WIDGET: {
         if (!mGdkWindow)
             return nullptr;
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -133,17 +133,16 @@ public:
     NS_IMETHOD         GetClientBounds(nsIntRect &aRect);
     virtual nsIntPoint GetClientOffset();
     NS_IMETHOD         SetForegroundColor(const nscolor &aColor);
     NS_IMETHOD         SetBackgroundColor(const nscolor &aColor);
     NS_IMETHOD         SetCursor(nsCursor aCursor);
     NS_IMETHOD         SetCursor(imgIContainer* aCursor,
                                  uint32_t aHotspotX, uint32_t aHotspotY);
     NS_IMETHOD         Invalidate(const nsIntRect &aRect);
-    virtual void       Update() MOZ_OVERRIDE;
     virtual void*      GetNativeData(uint32_t aDataType);
     NS_IMETHOD         SetTitle(const nsAString& aTitle);
     NS_IMETHOD         SetIcon(const nsAString& aIconSpec);
     NS_IMETHOD         SetWindowClass(const nsAString& xulWinType);
     virtual nsIntPoint WidgetToScreenOffset();
     NS_IMETHOD         EnableDragDrop(bool aEnable);
     NS_IMETHOD         CaptureMouse(bool aCapture);
     NS_IMETHOD         CaptureRollupEvents(nsIRollupListener *aListener,
--- a/widget/nsIAppShell.idl
+++ b/widget/nsIAppShell.idl
@@ -21,16 +21,34 @@ interface nsIAppShell : nsISupports
   void run();
 
   /**
    * Exit the handle event loop
    */
   void exit();
 
   /**
+   * Give hint to native event queue notification mechanism. If the native
+   * platform needs to tradeoff performance vs. native event starvation this
+   * hint tells the native dispatch code which to favor.  The default is to
+   * prevent native event starvation.
+   *
+   * Calls to this function may be nested. When the number of calls that pass
+   * PR_TRUE is subtracted from the number of calls that pass PR_FALSE is
+   * greater than 0, performance is given precedence over preventing event
+   * starvation.
+   *
+   * The starvationDelay arg is only used when favorPerfOverStarvation is
+   * PR_FALSE. It is the amount of time in milliseconds to wait before the
+   * PR_FALSE actually takes effect.
+   */
+  void favorPerformanceHint(in boolean favorPerfOverStarvation,
+                            in unsigned long starvationDelay);
+
+  /**
    * Suspends the use of additional platform-specific methods (besides the
    * nsIAppShell->run() event loop) to run Gecko events on the main
    * application thread.  Under some circumstances these "additional methods"
    * can cause Gecko event handlers to be re-entered, sometimes leading to
    * hangs and crashes.  Calls to suspendNative() and resumeNative() may be
    * nested.  On some platforms (those that don't use any "additional
    * methods") this will be a no-op.  Does not (in itself) stop Gecko events
    * from being processed on the main application thread.  But if the
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -95,18 +95,18 @@ typedef void* nsNativeWidget;
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-{ 0x0a157edd, 0xd70b, 0x4242, \
-  { 0xad, 0xd5, 0xcb, 0xce, 0x4c, 0xf3, 0x4b, 0x47 } }
+{ 0x67da44c4, 0xe21b, 0x4742, \
+  { 0x9c, 0x2b, 0x26, 0xc7, 0x70, 0x21, 0xde, 0x87 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -1192,21 +1192,16 @@ class nsIWidget : public nsISupports {
     NS_IMETHOD MakeFullScreen(bool aFullScreen) = 0;
 
     /**
      * Invalidate a specified rect for a widget so that it will be repainted
      * later.
      */
     NS_IMETHOD Invalidate(const nsIntRect & aRect) = 0;
 
-    /**
-     * Widget implementation may support synchronous painting.
-     */
-   virtual void Update() { }
-
     enum LayerManagerPersistence
     {
       LAYER_MANAGER_CURRENT = 0,
       LAYER_MANAGER_PERSISTENT
     };
 
     /**
      * Return the widget's LayerManager. The layer tree for that
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -2770,24 +2770,16 @@ NS_METHOD nsWindow::Invalidate(const nsI
     rect.right  = aRect.x + aRect.width;
     rect.bottom = aRect.y + aRect.height;
 
     VERIFY(::InvalidateRect(mWnd, &rect, FALSE));
   }
   return NS_OK;
 }
 
-void
-nsWindow::Update()
-{
-    if (!ShouldUseOffMainThreadCompositing() && mWnd) {
-        ::UpdateWindow(mWnd);
-    }
-}
-
 NS_IMETHODIMP
 nsWindow::MakeFullScreen(bool aFullScreen)
 {
   // taskbarInfo will be nullptr pre Windows 7 until Bug 680227 is resolved.
   nsCOMPtr<nsIWinTaskbar> taskbarInfo =
     do_GetService(NS_TASKBAR_CONTRACTID);
 
   mFullscreenMode = aFullScreen;
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -132,17 +132,16 @@ public:
   NS_IMETHOD              SetCursor(nsCursor aCursor);
   virtual nsresult        ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
   NS_IMETHOD              MakeFullScreen(bool aFullScreen);
   NS_IMETHOD              HideWindowChrome(bool aShouldHide);
   NS_IMETHOD              Invalidate(bool aEraseBackground = false,
                                      bool aUpdateNCArea = false,
                                      bool aIncludeChildren = false);
   NS_IMETHOD              Invalidate(const nsIntRect & aRect);
-  virtual void            Update() MOZ_OVERRIDE;
   virtual void*           GetNativeData(uint32_t aDataType);
   virtual void            FreeNativeData(void * data, uint32_t aDataType);
   NS_IMETHOD              SetTitle(const nsAString& aTitle);
   NS_IMETHOD              SetIcon(const nsAString& aIconSpec);
   virtual nsIntPoint      WidgetToScreenOffset();
   virtual nsIntSize       ClientToWindowSize(const nsIntSize& aClientSize);
   NS_IMETHOD              DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
                                         nsEventStatus& aStatus);
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -1263,24 +1263,16 @@ MetroWidget::Invalidate(const nsIntRect 
     rect.right  = aRect.x + aRect.width;
     rect.bottom = aRect.y + aRect.height;
     InvalidateRect(mWnd, &rect, FALSE);
   }
 
   return NS_OK;
 }
 
-void
-MetroWidget::Update()
-{
-    if (!ShouldUseOffMainThreadCompositing() && mWnd) {
-        ::UpdateWindow(mWnd);
-    }
-}
-
 nsTransparencyMode
 MetroWidget::GetTransparencyMode()
 {
   return mTransparencyMode;
 }
 
 void
 MetroWidget::SetTransparencyMode(nsTransparencyMode aMode)
--- a/widget/windows/winrt/MetroWidget.h
+++ b/widget/windows/winrt/MetroWidget.h
@@ -104,17 +104,16 @@ public:
   NS_IMETHOD    IsEnabled(bool *aState);
   NS_IMETHOD    GetBounds(nsIntRect &aRect);
   NS_IMETHOD    GetScreenBounds(nsIntRect &aRect);
   NS_IMETHOD    GetClientBounds(nsIntRect &aRect);
   NS_IMETHOD    Invalidate(bool aEraseBackground = false,
                 bool aUpdateNCArea = false,
                 bool aIncludeChildren = false);
   NS_IMETHOD    Invalidate(const nsIntRect & aRect);
-  virtual void  Update() MOZ_OVERRIDE;
   NS_IMETHOD    DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
                               nsEventStatus& aStatus);
   NS_IMETHOD    ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY);
   NS_IMETHOD    Move(double aX, double aY);
   NS_IMETHOD    Resize(double aWidth, double aHeight, bool aRepaint);
   NS_IMETHOD    Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint);
   NS_IMETHOD    SetFocus(bool aRaise);
   NS_IMETHOD    Enable(bool aState);
--- a/widget/xpwidgets/nsBaseAppShell.cpp
+++ b/widget/xpwidgets/nsBaseAppShell.cpp
@@ -17,17 +17,21 @@
 #define THREAD_EVENT_STARVATION_LIMIT PR_MillisecondsToInterval(20)
 
 NS_IMPL_ISUPPORTS3(nsBaseAppShell, nsIAppShell, nsIThreadObserver, nsIObserver)
 
 nsBaseAppShell::nsBaseAppShell()
   : mSuspendNativeCount(0)
   , mEventloopNestingLevel(0)
   , mBlockedWait(nullptr)
+  , mFavorPerf(0)
   , mNativeEventPending(0)
+  , mStarvationDelay(0)
+  , mSwitchTime(0)
+  , mLastNativeEventTime(0)
   , mEventloopNestingState(eEventloopNone)
   , mRunning(false)
   , mExiting(false)
   , mBlockNativeEvent(false)
 {
 }
 
 nsBaseAppShell::~nsBaseAppShell()
@@ -168,16 +172,30 @@ nsBaseAppShell::Exit(void)
   if (mRunning && !mExiting) {
     MessageLoop::current()->Quit();
   }
   mExiting = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsBaseAppShell::FavorPerformanceHint(bool favorPerfOverStarvation,
+                                     uint32_t starvationDelay)
+{
+  mStarvationDelay = PR_MillisecondsToInterval(starvationDelay);
+  if (favorPerfOverStarvation) {
+    ++mFavorPerf;
+  } else {
+    --mFavorPerf;
+    mSwitchTime = PR_IntervalNow();
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsBaseAppShell::SuspendNative()
 {
   ++mSuspendNativeCount;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBaseAppShell::ResumeNative()
@@ -227,40 +245,58 @@ nsBaseAppShell::OnProcessNextEvent(nsITh
     // back to it ASAP, but it seems a gecko event has caused us to
     // spin up a nested XPCOM event loop (eg. modal window), so we
     // really must start processing native events here again.
     mBlockNativeEvent = false;
     if (NS_HasPendingEvents(thr))
       OnDispatchedEvent(thr); // in case we blocked it earlier
   }
 
+  PRIntervalTime start = PR_IntervalNow();
+  PRIntervalTime limit = THREAD_EVENT_STARVATION_LIMIT;
+
   // Unblock outer nested wait loop (below).
   if (mBlockedWait)
     *mBlockedWait = false;
 
   bool *oldBlockedWait = mBlockedWait;
   mBlockedWait = &mayWait;
 
   // When mayWait is true, we need to make sure that there is an event in the
   // thread's event queue before we return.  Otherwise, the thread will block
   // on its event queue waiting for an event.
   bool needEvent = mayWait;
   // Reset prior to invoking DoProcessNextNativeEvent which might cause
   // NativeEventCallback to process gecko events.
   mProcessedGeckoEvents = false;
 
-  DoProcessNextNativeEvent(false, recursionDepth);
+  if (mFavorPerf <= 0 && start > mSwitchTime + mStarvationDelay) {
+    // Favor pending native events
+    PRIntervalTime now = start;
+    bool keepGoing;
+    do {
+      mLastNativeEventTime = now;
+      keepGoing = DoProcessNextNativeEvent(false, recursionDepth);
+    } while (keepGoing && ((now = PR_IntervalNow()) - start) < limit);
+  } else {
+    // Avoid starving native events completely when in performance mode
+    if (start - mLastNativeEventTime > limit) {
+      mLastNativeEventTime = start;
+      DoProcessNextNativeEvent(false, recursionDepth);
+    }
+  }
 
   while (!NS_HasPendingEvents(thr) && !mProcessedGeckoEvents) {
     // If we have been asked to exit from Run, then we should not wait for
     // events to process.  Note that an inner nested event loop causes
     // 'mayWait' to become false too, through 'mBlockedWait'.
     if (mExiting)
       mayWait = false;
 
+    mLastNativeEventTime = PR_IntervalNow();
     if (!DoProcessNextNativeEvent(mayWait, recursionDepth) || !mayWait)
       break;
   }
 
   mBlockedWait = oldBlockedWait;
 
   // Make sure that the thread event queue does not block on its monitor, as
   // it normally would do if it did not have any pending events.  To avoid
--- a/widget/xpwidgets/nsBaseAppShell.h
+++ b/widget/xpwidgets/nsBaseAppShell.h
@@ -114,17 +114,21 @@ private:
   nsCOMPtr<nsIRunnable> mDummyEvent;
   /**
    * mBlockedWait points back to a slot that controls the wait loop in
    * an outer OnProcessNextEvent invocation.  Nested calls always set
    * it to false to unblock an outer loop, since all events may
    * have been consumed by the inner event loop(s).
    */
   bool *mBlockedWait;
+  int32_t mFavorPerf;
   mozilla::Atomic<uint32_t> mNativeEventPending;
+  PRIntervalTime mStarvationDelay;
+  PRIntervalTime mSwitchTime;
+  PRIntervalTime mLastNativeEventTime;
   enum EventloopNestingState {
     eEventloopNone,  // top level thread execution
     eEventloopXPCOM, // innermost native event loop is ProcessNextNativeEvent
     eEventloopOther  // innermost native event loop is a native library/plugin etc
   };
   EventloopNestingState mEventloopNestingState;
   nsTArray<SyncSection> mSyncSections;
   bool mRunning;