Move deferred commit logic from WebViewImpl to Document.

This is more natural here, and will make it easy to add a bit that
tracks if a document would be in "deferred commits" mode even if its
not the main document. Then we can use that bit to trigger pipeline
throttling for iframes when they're loading avoiding FOUC in a sane
way.

This patch doesn't change any behavior and only moves the logic.

BUG=521692
TEST=DocumentLoadingRenderingTest.*

Review URL: https://codereview.chromium.org/1922793002

Cr-Commit-Position: refs/heads/master@{#389829}
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 9026eb7..6615aa5 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -610,6 +610,14 @@
     ContainerNode::childrenChanged(change);
     m_documentElement = ElementTraversal::firstWithin(*this);
 
+    // For non-HTML documents the willInsertBody notification won't happen
+    // so we resume as soon as we have a document element. Even for XHTML
+    // documents there may never be a <body> (since the parser won't always
+    // insert one), so we resume here too. That does mean XHTML documents make
+    // frames when there's only a <head>, but such documents are pretty rare.
+    if (m_documentElement && !isHTMLDocument())
+        beginLifecycleUpdatesIfRenderingReady();
+
     // Installs the viewport scrolling callback (the "applyScroll" in Scroll
     // Customization lingo) on the documentElement. This callback is
     // responsible for viewport related scroll actions like top controls
@@ -2497,6 +2505,18 @@
         documentElement()->appendChild(newBody, exceptionState);
 }
 
+void Document::willInsertBody()
+{
+    if (frame())
+        frame()->loader().client()->dispatchWillInsertBody();
+    // If we get to the <body> try to resume commits since we should have content
+    // to paint now.
+    // TODO(esprehn): Is this really optimal? We might start producing frames
+    // for very little content, should we wait for some heuristic like
+    // isVisuallyNonEmpty() ?
+    beginLifecycleUpdatesIfRenderingReady();
+}
+
 HTMLHeadElement* Document::head() const
 {
     Node* de = documentElement();
@@ -3017,8 +3037,14 @@
 {
     loadingTaskRunner()->postTask(BLINK_FROM_HERE, m_executeScriptsWaitingForResourcesTask->cancelAndCreate());
 
-    if (frame())
-        frame()->loader().client()->didRemoveAllPendingStylesheet();
+    if (isHTMLDocument() && body()) {
+        // For HTML if we have no more stylesheets to load and we're past the body
+        // tag, we should have something to paint so resume.
+        beginLifecycleUpdatesIfRenderingReady();
+    } else if (!isHTMLDocument() && documentElement()) {
+        // For non-HTML there is no body so resume as soon as the sheets are loaded.
+        beginLifecycleUpdatesIfRenderingReady();
+    }
 
     if (m_gotoAnchorNeededAfterStylesheetsLoad && view())
         view()->processUrlFragment(m_url);
@@ -4742,6 +4768,8 @@
         if (mainResourceWasAlreadyRequested)
             updateLayoutTree();
 
+        beginLifecycleUpdatesIfRenderingReady();
+
         frame->loader().finishedParsing();
 
         TRACE_EVENT_INSTANT1("devtools.timeline", "MarkDOMContent", TRACE_EVENT_SCOPE_THREAD, "data", InspectorMarkLoadEvent::data(frame));
@@ -4763,6 +4791,23 @@
     m_elementDataCache.clear();
 }
 
+void Document::beginLifecycleUpdatesIfRenderingReady()
+{
+    if (!isActive())
+        return;
+    if (!isRenderingReady())
+        return;
+    if (LocalFrame* frame = this->frame()) {
+        // Avoid pumping frames for the initially empty document.
+        if (!frame->loader().stateMachine()->committedFirstRealDocumentLoad())
+            return;
+        // The compositor will "defer commits" for the main frame until we
+        // explicitly request them.
+        if (frame->isMainFrame())
+            frame->page()->chromeClient().beginLifecycleUpdates();
+    }
+}
+
 Vector<IconURL> Document::iconURLs(int iconTypesMask)
 {
     IconURL firstFavicon;
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 63cd99c8..038fd039 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -757,6 +757,7 @@
     HTMLBodyElement* firstBodyElement() const;
 
     void setBody(HTMLElement*, ExceptionState&);
+    void willInsertBody();
 
     HTMLHeadElement* head() const;
 
@@ -1110,6 +1111,8 @@
 
     void detachParser();
 
+    void beginLifecycleUpdatesIfRenderingReady();
+
     bool isDocument() const final { return true; }
 
     void childrenChanged(const ChildrenChange&) override;
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameSetElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameSetElement.cpp
index 9d3ace97..0f04a788 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameSetElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameSetElement.cpp
@@ -198,7 +198,7 @@
 {
     if (insertionPoint->inShadowIncludingDocument() && document().frame()) {
         // A document using <frameset> likely won't literally have a body, but as far as the client is concerned, the frameset is effectively the body.
-        document().frame()->loader().client()->dispatchWillInsertBody();
+        document().willInsertBody();
     }
     return HTMLElement::insertedInto(insertionPoint);
 }
diff --git a/third_party/WebKit/Source/core/html/ImageDocument.cpp b/third_party/WebKit/Source/core/html/ImageDocument.cpp
index 37b578b..0d312fce 100644
--- a/third_party/WebKit/Source/core/html/ImageDocument.cpp
+++ b/third_party/WebKit/Source/core/html/ImageDocument.cpp
@@ -223,7 +223,7 @@
     HTMLBodyElement* body = HTMLBodyElement::create(*this);
     body->setAttribute(styleAttr, "margin: 0px;");
 
-    frame()->loader().client()->dispatchWillInsertBody();
+    willInsertBody();
 
     m_imageElement = HTMLImageElement::create(*this);
     m_imageElement->setAttribute(styleAttr, "-webkit-user-select: none");
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
index a00cd4fc..e40177f6 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
@@ -604,8 +604,8 @@
     HTMLElement* body = createHTMLElement(token);
     attachLater(currentNode(), body);
     m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body, token));
-    if (m_document && m_document->frame())
-        m_document->frame()->loader().client()->dispatchWillInsertBody();
+    if (m_document)
+        m_document->willInsertBody();
 }
 
 void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index 630ab62..a27b0bb 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -89,6 +89,8 @@
 
     void didOverscroll(const FloatSize&, const FloatSize&, const FloatPoint&, const FloatSize&) override {}
 
+    void beginLifecycleUpdates() override { }
+
     bool hadFormInteraction() const override { return false; }
 
     void startDragging(LocalFrame*, const WebDragData&, WebDragOperationsMask, const WebImage& dragImage, const WebPoint& dragImageOffset) {}
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
index 93e38b0ae..b7661fb 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
+++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -187,7 +187,6 @@
 
     virtual void didChangeScrollOffset() { }
     virtual void didUpdateCurrentHistoryItem() { }
-    virtual void didRemoveAllPendingStylesheet() { }
 
     virtual bool allowScript(bool enabledPerSettings) { return enabledPerSettings; }
     virtual bool allowScriptFromSource(bool enabledPerSettings, const KURL&) { return enabledPerSettings; }
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 83d8639..2fbe932 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -98,6 +98,8 @@
 
     virtual bool hadFormInteraction() const = 0;
 
+    virtual void beginLifecycleUpdates() = 0;
+
     // Start a system drag and drop operation.
     virtual void startDragging(LocalFrame*, const WebDragData&, WebDragOperationsMask, const WebImage& dragImage, const WebPoint& dragImageOffset) = 0;
     virtual bool acceptsLoadDrops() const = 0;
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index c3acd08f..8760f9c 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -934,6 +934,14 @@
     }
 }
 
+void ChromeClientImpl::beginLifecycleUpdates()
+{
+    if (WebLayerTreeView* treeView = m_webView->layerTreeView()) {
+        treeView->setDeferCommits(false);
+        treeView->setNeedsBeginFrame();
+    }
+}
+
 WebEventListenerProperties ChromeClientImpl::eventListenerProperties(WebEventListenerClass eventClass) const
 {
     if (WebLayerTreeView* treeView = m_webView->layerTreeView())
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h
index 6b134ff..819a9a8 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.h
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -62,6 +62,7 @@
     bool canTakeFocus(WebFocusType) override;
     void takeFocus(WebFocusType) override;
     void focusedNodeChanged(Node* fromNode, Node* toNode) override;
+    void beginLifecycleUpdates() override;
     bool hadFormInteraction() const override;
     void startDragging(LocalFrame*, const WebDragData&, WebDragOperationsMask, const WebImage& dragImage, const WebPoint& dragImageOffset) override;
     bool acceptsLoadDrops() const override;
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
index 9c91244d..6eaf477f 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -180,12 +180,6 @@
 {
     if (m_webFrame->client())
         m_webFrame->client()->didCreateDocumentElement(m_webFrame);
-
-    if (m_webFrame->parent())
-        return;
-
-    if (m_webFrame->viewImpl())
-        m_webFrame->viewImpl()->mainFrameDocumentElementAvailable();
 }
 
 void FrameLoaderClientImpl::runScriptsAtDocumentElementAvailable()
@@ -236,16 +230,6 @@
         m_webFrame->client()->didUpdateCurrentHistoryItem();
 }
 
-// TODO(dglazkov): Can this be plumbing be streamlined out?
-void FrameLoaderClientImpl::didRemoveAllPendingStylesheet()
-{
-    if (m_webFrame->parent())
-        return;
-
-    if (WebViewImpl* webview = m_webFrame->viewImpl())
-        webview->didRemoveAllPendingStylesheetsInMainFrameDocument();
-}
-
 bool FrameLoaderClientImpl::allowScript(bool enabledPerSettings)
 {
     if (m_webFrame->contentSettingsClient())
@@ -438,11 +422,6 @@
 
 void FrameLoaderClientImpl::dispatchDidFinishDocumentLoad()
 {
-    if (!m_webFrame->parent()) {
-        if (WebViewImpl* webview = m_webFrame->viewImpl())
-            webview->didFinishMainFrameDocumentLoad();
-    }
-
     // TODO(dglazkov): Sadly, workers are WebFrameClients, and they can totally
     // destroy themselves when didFinishDocumentLoad is invoked, and in turn destroy
     // the fake WebLocalFrame that they create, which means that you should not
@@ -985,12 +964,6 @@
 {
     if (m_webFrame->client())
         m_webFrame->client()->willInsertBody(m_webFrame);
-
-    if (m_webFrame->parent())
-        return;
-
-    if (m_webFrame->viewImpl())
-        m_webFrame->viewImpl()->willInsertMainFrameDocumentBody();
 }
 
 PassOwnPtr<WebServiceWorkerProvider> FrameLoaderClientImpl::createServiceWorkerProvider()
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
index 96fd156..cca979c75 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -136,7 +136,6 @@
         const KURL&, const WTF::String& mimeType, bool shouldPreferPlugInsForImages) override;
     void didChangeScrollOffset() override;
     void didUpdateCurrentHistoryItem() override;
-    void didRemoveAllPendingStylesheet() override;
     bool allowScript(bool enabledPerSettings) override;
     bool allowScriptFromSource(bool enabledPerSettings, const KURL& scriptURL) override;
     bool allowPlugins(bool enabledPerSettings) override;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 1b20cca..140dd2d 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -3984,79 +3984,6 @@
     m_userGestureObserved = false;
 }
 
-void WebViewImpl::mainFrameDocumentElementAvailable()
-{
-    // This check is necessary to avoid provisional frames
-    // (see WebLocalFrame::createProvisional) leaking
-    // their calls into WebViewImpl.
-    // See http://crbug.com/578349 for details.
-    // TODO(dcheng): Remove this when the provisional frames
-    // bite the dust.
-    if (!mainFrameImpl())
-        return;
-
-    // For non-HTML documents the willInsertBody notification won't happen
-    // so we resume as soon as we have a document element. Even for XHTML
-    // documents there may never be a <body> (since the parser won't always
-    // insert one), so we resume here too. That does mean XHTML documents make
-    // frames when there's only a <head>, but such documents are pretty rare.
-    if (!mainFrameImpl()->frame()->document()->isHTMLDocument())
-        resumeTreeViewCommitsIfRenderingReady();
-}
-
-void WebViewImpl::willInsertMainFrameDocumentBody()
-{
-    // This check is necessary to avoid provisional frames
-    // (see WebLocalFrame::createProvisional) leaking
-    // their calls into WebViewImpl.
-    // See http://crbug.com/578349 for details.
-    // TODO(dcheng): Remove this when the provisional frames
-    // bite the dust.
-    if (!mainFrameImpl())
-        return;
-
-    // If we get to the <body> try to resume commits since we should have content
-    // to paint now.
-    // TODO(esprehn): Is this really optimal? We might start producing frames
-    // for very little content, should we wait for some heuristic like
-    // isVisuallyNonEmpty() ?
-    resumeTreeViewCommitsIfRenderingReady();
-}
-
-void WebViewImpl::didFinishMainFrameDocumentLoad()
-{
-    resumeTreeViewCommitsIfRenderingReady();
-}
-
-void WebViewImpl::didRemoveAllPendingStylesheetsInMainFrameDocument()
-{
-    Document& document = *mainFrameImpl()->frame()->document();
-
-    // For HTML if we have no more stylesheets to load and we're past the body
-    // tag, we should have something to paint so resume.
-    if (document.isHTMLDocument() && !document.body())
-        return;
-
-    // For non-HTML there is no body so resume as soon as the sheets are loaded.
-    if (!document.isHTMLDocument() && !document.documentElement())
-        return;
-
-    resumeTreeViewCommitsIfRenderingReady();
-}
-
-void WebViewImpl::resumeTreeViewCommitsIfRenderingReady()
-{
-    LocalFrame* frame = mainFrameImpl()->frame();
-    if (!frame->loader().stateMachine()->committedFirstRealDocumentLoad())
-        return;
-    if (!frame->document()->isRenderingReady())
-        return;
-    if (m_layerTreeView) {
-        m_layerTreeView->setDeferCommits(false);
-        m_layerTreeView->setNeedsBeginFrame();
-    }
-}
-
 void WebViewImpl::postLayoutResize(WebLocalFrameImpl* webframe)
 {
     FrameView* view = webframe->frame()->view();
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h
index 0bb1a40..a087675 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.h
+++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -374,10 +374,6 @@
     // unless the view did not need a layout.
     void layoutUpdated(WebLocalFrameImpl*);
 
-    void mainFrameDocumentElementAvailable();
-    void willInsertMainFrameDocumentBody();
-    void didRemoveAllPendingStylesheetsInMainFrameDocument();
-    void didFinishMainFrameDocumentLoad();
     void didChangeContentsSize();
     void pageScaleFactorChanged();
 
@@ -536,7 +532,6 @@
 
     float maximumLegiblePageScale() const;
     void refreshPageScaleFactorAfterLayout();
-    void resumeTreeViewCommitsIfRenderingReady();
     IntSize contentsSize() const;
 
     void performResize();