Bug 1396097 Part 1: Detect synchronous layout requests when stylesheets are still loading, and output a console warning. draft
authorBrad Werth <bwerth@mozilla.com>
Fri, 01 Sep 2017 16:17:57 -0700
changeset 657796 7f3cfd3cc57cb21b735787a170573bb0b42b3d79
parent 657795 f8f7c6f13bf3e33fbb42ce9d88a513df97a28b2b
child 729517 3237f6fd7dfff3034ec50b8ca89d8d7e8dae6c8f
push id77619
push userbwerth@mozilla.com
push dateFri, 01 Sep 2017 23:16:42 +0000
bugs1396097
milestone57.0a1
Bug 1396097 Part 1: Detect synchronous layout requests when stylesheets are still loading, and output a console warning. MozReview-Commit-ID: CSsXkPHRQuH
dom/base/nsContentSink.cpp
layout/base/ServoRestyleManager.cpp
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -30,16 +30,17 @@
 #include "nsIAtom.h"
 #include "nsGkAtoms.h"
 #include "nsNetCID.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheContainer.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsIScriptError.h"
 #include "nsICookieService.h"
 #include "nsContentUtils.h"
 #include "nsNodeInfoManager.h"
 #include "nsIAppShell.h"
 #include "nsIWidget.h"
 #include "nsWidgetsCID.h"
 #include "nsIDOMNode.h"
 #include "mozAutoDocUpdate.h"
@@ -1250,18 +1251,33 @@ nsContentSink::StartLayout(bool aIgnoreP
 {
   if (mLayoutStarted) {
     // Nothing to do here
     return;
   }
 
   mDeferredLayoutStart = true;
 
-  if (!aIgnorePendingSheets && WaitForPendingSheets()) {
-    // Bail out; we'll start layout when the sheets load
+  if (aIgnorePendingSheets) {
+    // This is a Flash of Unstyled Content (FOUC) situation. Layout is being
+    // synchronously requested before stylesheets are loaded. This will cause
+    // layout and paint to occur, only to be quickly replaced by a more complete
+    // and probably very different layout and paint.
+    //
+    // This is possible when an early-running script requests a property that
+    // triggers layout. We output a console warning to assist site developers
+    // in diagnosing the problem.
+    nsContentUtils::ReportToConsoleNonLocalized(
+      NS_LITERAL_STRING("Synchronous layout requested before stylesheets are loaded."),
+      nsIScriptError::warningFlag,
+      NS_LITERAL_CSTRING("layout"),
+      mDocument);
+  } else if (WaitForPendingSheets()) {
+    // If we can't ignore pending sheets, and we have some pending then we
+    // need to bail out; we'll start layout when the sheets load.
     return;
   }
 
   mDeferredLayoutStart = false;
 
   // Notify on all our content.  If none of our presshells have started layout
   // yet it'll be a no-op except for updating our data structures, a la
   // UpdateChildCounts() (because we don't want to double-notify on whatever we
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -101,18 +101,19 @@ ExpectedOwnerForChild(const nsIFrame& aF
 
 void
 ServoRestyleState::AssertOwner(const ServoRestyleState& aParent) const
 {
   MOZ_ASSERT(mOwner);
   MOZ_ASSERT(!mOwner->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
   // We allow aParent.mOwner to be null, for cases when we're not starting at
   // the root of the tree.
+  const nsIFrame* ownersOwner = ExpectedOwnerForChild(*mOwner);
   MOZ_ASSERT_IF(aParent.mOwner,
-                ExpectedOwnerForChild(*mOwner) == aParent.mOwner);
+                ownersOwner == aParent.mOwner);
 }
 
 nsChangeHint
 ServoRestyleState::ChangesHandledFor(const nsIFrame& aFrame) const
 {
   if (!mOwner) {
     MOZ_ASSERT(!mChangesHandled);
     return mChangesHandled;