Bug 930793 - Remove favor performance mode, r=avih,roc
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Sun, 12 Apr 2015 23:08:55 +0300
changeset 238773 1b8f36a7ee321ca62cf87424910d0e2ed6fed076
parent 238772 e82a14c4de34a1427052f3fcc6ef23d97c34c5a8
child 238774 2c9708e6b54df65eb3be8a930e40425e560f30b1
child 238840 858ea94746eedc4b65734f8ceedfff7021940cb2
push id12336
push usercbook@mozilla.com
push dateMon, 13 Apr 2015 10:11:10 +0000
treeherderfx-team@43bde386bad8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersavih, roc
bugs930793
milestone40.0a1
Bug 930793 - Remove favor performance mode, r=avih,roc
docshell/base/nsDocShell.cpp
dom/base/nsContentSink.cpp
dom/base/nsContentSink.h
dom/tests/mochitest/general/test_vibrator.html
dom/tests/mochitest/pointerlock/file_screenClientXYConst.html
layout/base/nsRefreshDriver.cpp
view/nsViewManager.cpp
view/nsViewManager.h
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/nsBaseAppShell.cpp
widget/nsBaseAppShell.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
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -195,18 +195,16 @@
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "nsPerformance.h"
 
 #ifdef MOZ_TOOLKIT_SEARCH
 #include "nsIBrowserSearchService.h"
 #endif
 
-static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
-
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
 //#define DEBUG_DOCSHELL_FOCUS
 #define DEBUG_PAGE_CACHE
 #endif
 
 #ifdef XP_WIN
 #include <process.h>
 #define getpid _getpid
@@ -217,19 +215,16 @@ 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;
@@ -250,28 +245,16 @@ 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 aPerfOverStarvation)
-{
-  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
-  if (appShell) {
-    appShell->FavorPerformanceHint(
-      aPerfOverStarvation,
-      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"
 
@@ -7536,24 +7519,16 @@ 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) {
@@ -8673,22 +8648,16 @@ 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 (oldCv && newCv) {
     newCv->SetMinFontSize(minFontSize);
     newCv->SetTextZoom(textZoom);
     newCv->SetFullZoom(pageZoom);
     newCv->SetAuthorStyleDisabled(styleDisabled);
   }
 
   nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
@@ -9091,26 +9060,16 @@ nsDocShell::CreateContentViewer(const ns
       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, aRequest, mCurrentURI, 0);
   }
 
   return NS_OK;
 }
 
 nsresult
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -196,17 +196,16 @@ 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(CSSStyleSheet* aSheet,
                                 bool aWasAlternate,
@@ -1404,25 +1403,16 @@ 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,
@@ -1489,22 +1479,16 @@ 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()
 {
@@ -1532,17 +1516,16 @@ 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/dom/base/nsContentSink.h
+++ b/dom/base/nsContentSink.h
@@ -234,18 +234,16 @@ 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/dom/tests/mochitest/general/test_vibrator.html
+++ b/dom/tests/mochitest/general/test_vibrator.html
@@ -60,17 +60,17 @@ function tests(aEnabled) {
   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 < 10000; i++) {
+  for (var i = 0; i < 1000; i++) {
     navigator.vibrate([100, 100]);
   }
   ok(true, "Didn't crash after issuing a lot of vibrate() calls.");
   if(!aEnabled)
     SimpleTest.finish();
 }
 
 // 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
@@ -1717,17 +1717,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();
+    vm->ProcessPendingUpdates(nsViewManager::eTrySyncUpdate);
 #ifdef MOZ_DUMP_PAINTING
     if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
       printf_stderr("Ending ProcessPendingUpdates\n");
     }
 #endif
     for (uint32_t i = 0; i < profilingDocShells.Length(); i ++) {
       profilingDocShells[i]->AddProfileTimelineMarker("Paint",
                                                       TRACING_INTERVAL_END);
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -672,17 +672,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();
+      ProcessPendingUpdates(eNoSyncUpdate);
       // Re-get the view pointer here since the ProcessPendingUpdates might have
       // destroyed it during CallWillPaintOnObservers.
       view = nsView::GetViewFor(aWidget);
       if (view) {
         view->SetForcedRepaint(false);
       }
     }
   }
@@ -1055,31 +1055,39 @@ nsIntRect nsViewManager::ViewToWidget(ns
 
 void
 nsViewManager::IsPainting(bool& aIsPainting)
 {
   aIsPainting = IsPainting();
 }
 
 void
-nsViewManager::ProcessPendingUpdates()
+nsViewManager::ProcessPendingUpdates(UpdatingMode aMode)
 {
   if (!IsRootVM()) {
-    RootViewManager()->ProcessPendingUpdates();
+    RootViewManager()->ProcessPendingUpdates(aMode);
     return;
   }
 
   // Flush things like reflows by calling WillPaint on observer presShells.
   if (mPresShell) {
     mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
 
     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/view/nsViewManager.h
+++ b/view/nsViewManager.h
@@ -298,21 +298,26 @@ 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();
+  void ProcessPendingUpdates(UpdatingMode aMode);
 
   /**
    * Just update widget geometry without flushing the dirty region
    */
   void UpdateWidgetGeometry();
 
   int32_t AppUnitsPerDevPixel() const
   {
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1692,16 +1692,24 @@ nsWindow::Invalidate(const nsIntRect &aR
     gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
 
     LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
              rect.x, rect.y, rect.width, rect.height));
 
     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
@@ -128,16 +128,17 @@ public:
     NS_IMETHOD         GetScreenBounds(nsIntRect &aRect) override;
     NS_IMETHOD         GetClientBounds(nsIntRect &aRect) override;
     virtual mozilla::gfx::IntSize GetClientSize() override;
     virtual nsIntPoint GetClientOffset() override;
     NS_IMETHOD         SetCursor(nsCursor aCursor) override;
     NS_IMETHOD         SetCursor(imgIContainer* aCursor,
                                  uint32_t aHotspotX, uint32_t aHotspotY) override;
     NS_IMETHOD         Invalidate(const nsIntRect &aRect) override;
+    virtual void       Update() override;
     virtual void*      GetNativeData(uint32_t aDataType) override;
     void               SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
     NS_IMETHOD         SetTitle(const nsAString& aTitle) override;
     NS_IMETHOD         SetIcon(const nsAString& aIconSpec) override;
     NS_IMETHOD         SetWindowClass(const nsAString& xulWinType) override;
     virtual mozilla::LayoutDeviceIntPoint WidgetToScreenOffset() override;
     NS_IMETHOD         EnableDragDrop(bool aEnable) override;
     NS_IMETHOD         CaptureMouse(bool aCapture) override;
--- a/widget/nsBaseAppShell.cpp
+++ b/widget/nsBaseAppShell.cpp
@@ -20,21 +20,17 @@
 #define THREAD_EVENT_STARVATION_LIMIT PR_MillisecondsToInterval(20)
 
 NS_IMPL_ISUPPORTS(nsBaseAppShell, nsIAppShell, nsIThreadObserver, nsIObserver)
 
 nsBaseAppShell::nsBaseAppShell()
   : mSuspendNativeCount(0)
   , mEventloopNestingLevel(0)
   , mBlockedWait(nullptr)
-  , mFavorPerf(0)
   , mNativeEventPending(false)
-  , mStarvationDelay(0)
-  , mSwitchTime(0)
-  , mLastNativeEventTime(0)
   , mEventloopNestingState(eEventloopNone)
   , mRunning(false)
   , mExiting(false)
   , mBlockNativeEvent(false)
 {
 }
 
 nsBaseAppShell::~nsBaseAppShell()
@@ -175,30 +171,16 @@ 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()
@@ -248,58 +230,40 @@ 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;
 
-  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);
-    }
-  }
+  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/nsBaseAppShell.h
+++ b/widget/nsBaseAppShell.h
@@ -117,21 +117,17 @@ 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<bool> 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;
--- a/widget/nsIAppShell.idl
+++ b/widget/nsIAppShell.idl
@@ -7,48 +7,30 @@
 #include "nsISupports.idl"
 
 interface nsIRunnable;
 
 /**
  * Interface for the native event system layer.  This interface is designed
  * to be used on the main application thread only.
  */
-[uuid(2d10ca53-f143-439a-bb2e-c1fbc71f6a05)]
+[uuid(78dc2b13-5de6-42f3-af57-2535f7fdb93e)]
 interface nsIAppShell : nsISupports
 {
   /**
    * Enter an event loop.  Don't leave until exit() is called.
    */
   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
@@ -109,18 +109,18 @@ typedef void* nsNativeWidget;
 #if defined(MOZ_WIDGET_GTK)
 // set/get nsPluginNativeWindowGtk, e10s specific
 #define NS_NATIVE_PLUGIN_OBJECT_PTR    104
 #endif
 // See RegisterPluginWindowForRemoteUpdates
 #define NS_NATIVE_PLUGIN_ID            105
 
 #define NS_IWIDGET_IID \
-{ 0x316E4600, 0x15DB, 0x47AE, \
-  { 0xBF, 0xE4, 0x5B, 0xCD, 0xFF, 0x80, 0x80, 0x83 } };
+{ 0x7a4ece50, 0x5c52, 0x47c2, \
+  { 0x8c, 0x9e, 0x32, 0xd2, 0x5a, 0x27, 0x53, 0x34 } }
 
 /*
  * 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
@@ -1498,16 +1498,21 @@ class nsIWidget : public nsISupports {
     NS_IMETHOD MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen = nullptr) = 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
@@ -2821,16 +2821,24 @@ 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, nsIScreen* aTargetScreen)
 {
   // 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
@@ -129,16 +129,17 @@ public:
   NS_IMETHOD              SetCursor(nsCursor aCursor);
   virtual nsresult        ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
   NS_IMETHOD              MakeFullScreen(bool aFullScreen, nsIScreen* aScreen = nullptr);
   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() 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 mozilla::LayoutDeviceIntPoint WidgetToScreenOffset();
   virtual mozilla::LayoutDeviceIntSize ClientToWindowSize(const mozilla::LayoutDeviceIntSize& aClientSize) override;
   NS_IMETHOD              DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
                                         nsEventStatus& aStatus);
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -1177,16 +1177,24 @@ MetroWidget::Invalidate(bool aEraseBackg
   nsIntRect rect;
   if (mView) {
     mView->GetBounds(rect);
   }
   Invalidate(rect);
   return NS_OK;
 }
 
+void
+MetroWidget::Update()
+{
+  if (!ShouldUseOffMainThreadCompositing() && mWnd) {
+    ::UpdateWindow(mWnd);
+  }
+}
+
 NS_IMETHODIMP
 MetroWidget::Invalidate(const nsIntRect & aRect)
 {
   if (mWnd) {
     RECT rect;
     rect.left   = aRect.x;
     rect.top    = aRect.y;
     rect.right  = aRect.x + aRect.width;
--- a/widget/windows/winrt/MetroWidget.h
+++ b/widget/windows/winrt/MetroWidget.h
@@ -105,16 +105,17 @@ 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() 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);