Hack: Delay layout initialization until parsing finishes. draft
authorBobby Holley <bobbyholley@gmail.com>
Mon, 08 Aug 2016 09:29:30 +1000
changeset 403154 cdf240895d30d37d2232b52e2f46df0279f0369f
parent 403153 21e7ef7c34b24fd45ef1ea45d3b612190496b7bf
child 403155 15ce8b6b435fe1f122d68ea2394eb8bbab7474c3
push id26836
push userxquan@mozilla.com
push dateFri, 19 Aug 2016 06:15:33 +0000
milestone51.0a1
Hack: Delay layout initialization until parsing finishes. MozReview-Commit-ID: LuVu99QPXcf
dom/base/nsContentSink.cpp
dom/base/nsContentSink.h
dom/html/nsHTMLContentSink.cpp
parser/html/nsHtml5TreeOpExecutor.cpp
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -216,23 +216,17 @@ nsContentSink::StyleSheetLoaded(StyleShe
     NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?");
     --mPendingSheetCount;
 
     if (mPendingSheetCount == 0 &&
         (mDeferredLayoutStart || mDeferredFlushTags)) {
       if (mDeferredFlushTags) {
         FlushTags();
       }
-      if (mDeferredLayoutStart) {
-        // We might not have really started layout, since this sheet was still
-        // loading.  Do it now.  Probably doesn't matter whether we do this
-        // before or after we unblock scripts, but before feels saner.  Note
-        // that if mDeferredLayoutStart is true, that means any subclass
-        // StartLayout() stuff that needs to happen has already happened, so we
-        // don't need to worry about it.
+      if (mModelBuilt) {
         StartLayout(false);
       }
 
       // Go ahead and try to scroll to our ref if we have one
       ScrollToRef();
     }
     
     mScriptLoader->RemoveParserBlockingScriptExecutionBlocker();
@@ -1460,16 +1454,18 @@ nsContentSink::EndUpdate(nsIDocument *aD
   if (!--mInNotification) {
     UpdateChildCounts();
   }
 }
 
 void
 nsContentSink::DidBuildModelImpl(bool aTerminated)
 {
+  mModelBuilt = true;
+
   if (mDocument) {
     MOZ_ASSERT(aTerminated ||
                mDocument->GetReadyStateEnum() ==
                nsIDocument::READYSTATE_LOADING, "Bad readyState");
     mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
   }
 
   if (mScriptLoader) {
@@ -1484,16 +1480,26 @@ nsContentSink::DidBuildModelImpl(bool aT
   if (mNotificationTimer) {
     SINK_TRACE(static_cast<LogModule*>(gContentSinkLogModuleInfo),
                SINK_TRACE_REFLOW,
                ("nsContentSink::DidBuildModel: canceling notification "
                 "timeout"));
     mNotificationTimer->Cancel();
     mNotificationTimer = 0;
   }	
+
+  if (mPendingSheetCount == 0) {
+    // We might not have really started layout, since this sheet was still
+    // loading.  Do it now.  Probably doesn't matter whether we do this
+    // before or after we unblock scripts, but before feels saner.  Note
+    // that if mDeferredLayoutStart is true, that means any subclass
+    // StartLayout() stuff that needs to happen has already happened, so we
+    // don't need to worry about it.
+    StartLayout(false);
+  }
 }
 
 void
 nsContentSink::DropParserAndPerfHint(void)
 {
   if (!mParser) {
     // Make sure we don't unblock unload too many times
     return;
--- a/dom/base/nsContentSink.h
+++ b/dom/base/nsContentSink.h
@@ -333,16 +333,18 @@ protected:
   int32_t mInNotification;
   uint32_t mUpdatesInNotification;
 
   uint32_t mPendingSheetCount;
 
   nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> >
     mProcessLinkHeaderEvent;
 
+  bool mModelBuilt;
+
   // Do we notify based on time?
   static bool sNotifyOnTimer;
   // Back off timer notification after count.
   static int32_t sBackoffCount;
   // Notification interval in microseconds
   static int32_t sNotificationInterval;
   // How many times to deflect in interactive/perf modes
   static int32_t sInteractiveDeflectCount;
--- a/dom/html/nsHTMLContentSink.cpp
+++ b/dom/html/nsHTMLContentSink.cpp
@@ -903,18 +903,16 @@ HTMLContentSink::OpenBody()
     }
     mCurrentContext->mStack[parentIndex].mNumFlushed = childCount;
     if (mUpdatesInNotification > 1) {
       UpdateChildCounts();
     }
     mUpdatesInNotification = oldUpdates;
   }
 
-  StartLayout(false);
-
   return NS_OK;
 }
 
 nsresult
 HTMLContentSink::CloseBody()
 {
   // Flush out anything that's left
   mCurrentContext->FlushTags();
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -604,18 +604,16 @@ nsHtml5TreeOpExecutor::StartLayout() {
 
   EndDocUpdate();
 
   if (MOZ_UNLIKELY(!mParser)) {
     // got terminate
     return;
   }
 
-  nsContentSink::StartLayout(false);
-
   BeginDocUpdate();
 }
 
 /**
  * The reason why this code is here and not in the tree builder even in the 
  * main-thread case is to allow the control to return from the tokenizer 
  * before scripts run. This way, the tokenizer is not invoked re-entrantly 
  * although the parser is.