Title: [214435] trunk
Revision
214435
Author
an...@apple.com
Date
2017-03-27 15:56:32 -0700 (Mon, 27 Mar 2017)

Log Message

Source/WebCore:
Allow the page to render before <link> stylesheet tags in body
https://bugs.webkit.org/show_bug.cgi?id=149157
<rdar://problem/24658830>

Reviewed by Simon Fraser.

Currently we block style and renderer building completely if document has any loading
stylesheets. In case a script queries something layout dependent we construct the render
tree with whatever style we have but block painting in it.

This patch changes behavior so that a loading stylesheet in body only blocks rendering for elements
that are after it. The expectation is that such stylesheets rarely affect elements before them
and the elements can be rendered without causing ugly visible styling changes.

The patch replaces the old flash-of-unstyled-content (FOUC) preventation mechanism with a more
fine-grained one. Paint blocking is now done on per-renderer basis with based on isNonFinal flag in
RenderStyle.

For stylesheets in head the behavior should be largely unchanged.

Test: http/tests/incremental/stylesheet-body-incremental-rendering.html

* css/StyleResolver.cpp:
(WebCore::StyleResolver::pseudoStyleRulesForElement):
* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::resolveStyle):
(WebCore::Document::updateLayoutIgnorePendingStylesheets):

    Remove the old FOUC preventation state tracking.

(WebCore::Document::shouldScheduleLayout):
(WebCore::Document::didRemoveAllPendingStylesheet):

    Repaints will now get triggered by the normal style mechanism.

* dom/Document.h:
(WebCore::Document::hasNodesWithNonFinalStyle):
(WebCore::Document::setHasNodesWithNonFinalStyle):

    Track if we need to recompute the style later because non-final or unstyled elements.

(WebCore::Document::didLayoutWithPendingStylesheets): Deleted.
(WebCore::Document::hasNodesWithPlaceholderStyle): Deleted.
(WebCore::Document::setHasNodesWithPlaceholderStyle): Deleted.
* html/HTMLFrameSetElement.cpp:
(WebCore::HTMLFrameSetElement::rendererIsNeeded):
* page/FrameView.cpp:
(WebCore::FrameView::qualifiesAsVisuallyNonEmpty):

    Don't qualify as visually non-empty if we have loading stylesheets in head (even if there is
    a fouc-prevented render tree).

(WebCore::FrameView::fireLayoutRelatedMilestonesIfNeeded):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::paintContents):

    Instead of a global test, block painting if isNonFinal is set in the renderer's style.

* rendering/RenderLayer.cpp:
(WebCore::shouldSuppressPaintingLayer):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::changeRequiresRepaint):

    The isNonFinal flag prevents painting so we need to trigger repaint when it gets cleared.

* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::isNotFinal):
(WebCore::RenderStyle::setIsNotFinal):
(WebCore::RenderStyle::isPlaceholderStyle): Deleted.
(WebCore::RenderStyle::setIsPlaceholderStyle): Deleted.

    There is no need for placeholder styles anymore. Reuse the bit for isNotFinal.

* rendering/style/StyleRareNonInheritedData.cpp:
(WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
(WebCore::StyleRareNonInheritedData::operator==):
* rendering/style/StyleRareNonInheritedData.h:
* style/StyleScope.cpp:
(WebCore::Style::Scope::analyzeStyleSheetChange):
(WebCore::Style::Scope::updateActiveStyleSheets):
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::styleForElement):
(WebCore::Style::TreeResolver::resolveElement):

    If we have seens a loading stylesheet and don't have a renderer yet don't style the element.
    In case there is a renderer or we are ignoring pending sheets, resolve the style normally
    but mark it as non-final.

(WebCore::Style::makePlaceholderStyle): Deleted.

LayoutTests:
Loading in-body stylesheets should not block rendering of elements before them
https://bugs.webkit.org/show_bug.cgi?id=169345

Reviewed by Simon Fraser.

* http/tests/incremental/resources/delayed-css.php: Added.
* http/tests/incremental/stylesheet-body-incremental-rendering-expected.html: Added.
* http/tests/incremental/stylesheet-body-incremental-rendering.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (214434 => 214435)


--- trunk/LayoutTests/ChangeLog	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/LayoutTests/ChangeLog	2017-03-27 22:56:32 UTC (rev 214435)
@@ -1,3 +1,14 @@
+2017-03-27  Antti Koivisto  <an...@apple.com>
+
+        Loading in-body stylesheets should not block rendering of elements before them
+        https://bugs.webkit.org/show_bug.cgi?id=169345
+
+        Reviewed by Simon Fraser.
+
+        * http/tests/incremental/resources/delayed-css.php: Added.
+        * http/tests/incremental/stylesheet-body-incremental-rendering-expected.html: Added.
+        * http/tests/incremental/stylesheet-body-incremental-rendering.html: Added.
+
 2017-03-27  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Test variation font ranges in the CSS Font Loading API

Added: trunk/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering-expected.html (0 => 214435)


--- trunk/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering-expected.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering-expected.html	2017-03-27 22:56:32 UTC (rev 214435)
@@ -0,0 +1,6 @@
+<div style="width:100px; height:100px; background-color:green"></div>
+<div style="width:100px; height:100px; background-color:green"></div>
+<p>
+Before stylesheet load: (repaint rects (rect 8 8 100 100) )<br>
+After stylesheet load: (repaint rects (rect 8 108 100 100) )<br>
+</p>

Added: trunk/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering.html (0 => 214435)


--- trunk/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering.html	2017-03-27 22:56:32 UTC (rev 214435)
@@ -0,0 +1,24 @@
+<body>
+<script>
+document.body.offsetWidth;
+
+internals.startTrackingRepaints();
+let initialRects;
+setTimeout(() => {
+   initialRects = internals.repaintRectsAsText();
+   internals.stopTrackingRepaints();
+   internals.startTrackingRepaints();
+}, 0);
+
+document.body._onload_ = () => {
+    let finalRects = internals.repaintRectsAsText();
+    internals.stopTrackingRepaints();
+    document.body.innerHTML += `<p>
+        Before stylesheet load: ${initialRects}<br>
+        After stylesheet load: ${finalRects}<br>
+    </p>`;
+};
+</script>
+<div style="width:100px; height:100px; background-color:green"></div>
+<link rel="stylesheet" href=""
+<div class=delayed style="width:100px; height:100px; background-color:red"></div>

Modified: trunk/Source/WebCore/ChangeLog (214434 => 214435)


--- trunk/Source/WebCore/ChangeLog	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/ChangeLog	2017-03-27 22:56:32 UTC (rev 214435)
@@ -1,3 +1,96 @@
+2017-03-27  Antti Koivisto  <an...@apple.com>
+
+        Allow the page to render before <link> stylesheet tags in body
+        https://bugs.webkit.org/show_bug.cgi?id=149157
+        <rdar://problem/24658830>
+
+        Reviewed by Simon Fraser.
+
+        Currently we block style and renderer building completely if document has any loading
+        stylesheets. In case a script queries something layout dependent we construct the render
+        tree with whatever style we have but block painting in it.
+
+        This patch changes behavior so that a loading stylesheet in body only blocks rendering for elements
+        that are after it. The expectation is that such stylesheets rarely affect elements before them
+        and the elements can be rendered without causing ugly visible styling changes.
+
+        The patch replaces the old flash-of-unstyled-content (FOUC) preventation mechanism with a more
+        fine-grained one. Paint blocking is now done on per-renderer basis with based on isNonFinal flag in
+        RenderStyle.
+
+        For stylesheets in head the behavior should be largely unchanged.
+
+        Test: http/tests/incremental/stylesheet-body-incremental-rendering.html
+
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::pseudoStyleRulesForElement):
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::resolveStyle):
+        (WebCore::Document::updateLayoutIgnorePendingStylesheets):
+
+            Remove the old FOUC preventation state tracking.
+
+        (WebCore::Document::shouldScheduleLayout):
+        (WebCore::Document::didRemoveAllPendingStylesheet):
+
+            Repaints will now get triggered by the normal style mechanism.
+
+        * dom/Document.h:
+        (WebCore::Document::hasNodesWithNonFinalStyle):
+        (WebCore::Document::setHasNodesWithNonFinalStyle):
+
+            Track if we need to recompute the style later because non-final or unstyled elements.
+
+        (WebCore::Document::didLayoutWithPendingStylesheets): Deleted.
+        (WebCore::Document::hasNodesWithPlaceholderStyle): Deleted.
+        (WebCore::Document::setHasNodesWithPlaceholderStyle): Deleted.
+        * html/HTMLFrameSetElement.cpp:
+        (WebCore::HTMLFrameSetElement::rendererIsNeeded):
+        * page/FrameView.cpp:
+        (WebCore::FrameView::qualifiesAsVisuallyNonEmpty):
+
+            Don't qualify as visually non-empty if we have loading stylesheets in head (even if there is
+            a fouc-prevented render tree).
+
+        (WebCore::FrameView::fireLayoutRelatedMilestonesIfNeeded):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::paintContents):
+
+            Instead of a global test, block painting if isNonFinal is set in the renderer's style.
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::shouldSuppressPaintingLayer):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::changeRequiresRepaint):
+
+            The isNonFinal flag prevents painting so we need to trigger repaint when it gets cleared.
+
+        * rendering/style/RenderStyle.h:
+        (WebCore::RenderStyle::isNotFinal):
+        (WebCore::RenderStyle::setIsNotFinal):
+        (WebCore::RenderStyle::isPlaceholderStyle): Deleted.
+        (WebCore::RenderStyle::setIsPlaceholderStyle): Deleted.
+
+            There is no need for placeholder styles anymore. Reuse the bit for isNotFinal.
+
+        * rendering/style/StyleRareNonInheritedData.cpp:
+        (WebCore::StyleRareNonInheritedData::StyleRareNonInheritedData):
+        (WebCore::StyleRareNonInheritedData::operator==):
+        * rendering/style/StyleRareNonInheritedData.h:
+        * style/StyleScope.cpp:
+        (WebCore::Style::Scope::analyzeStyleSheetChange):
+        (WebCore::Style::Scope::updateActiveStyleSheets):
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::TreeResolver::styleForElement):
+        (WebCore::Style::TreeResolver::resolveElement):
+
+            If we have seens a loading stylesheet and don't have a renderer yet don't style the element.
+            In case there is a renderer or we are ignoring pending sheets, resolve the style normally
+            but mark it as non-final.
+
+        (WebCore::Style::makePlaceholderStyle): Deleted.
+
 2017-03-27  Myles C. Maxfield  <mmaxfi...@apple.com>
 
         Test variation font ranges in the CSS Font Loading API

Modified: trunk/Source/WebCore/css/StyleResolver.cpp (214434 => 214435)


--- trunk/Source/WebCore/css/StyleResolver.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/css/StyleResolver.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -1123,8 +1123,8 @@
 
 Vector<RefPtr<StyleRule>> StyleResolver::pseudoStyleRulesForElement(const Element* element, PseudoId pseudoId, unsigned rulesToInclude)
 {
-    if (!element || !element->document().haveStylesheetsLoaded())
-        return Vector<RefPtr<StyleRule>>();
+    if (!element)
+        return { };
 
     m_state = State(*element, nullptr);
 

Modified: trunk/Source/WebCore/dom/Document.cpp (214434 => 214435)


--- trunk/Source/WebCore/dom/Document.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/dom/Document.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -1725,7 +1725,8 @@
 
         if (type == ResolveStyleType::Rebuild) {
             // This may get set again during style resolve.
-            m_hasNodesWithPlaceholderStyle = false;
+            m_hasNodesWithNonFinalStyle = false;
+            m_hasNodesWithMissingStyle = false;
 
             auto documentStyle = Style::resolveForDocument(*this);
 
@@ -1761,6 +1762,9 @@
         }
 
         updatedCompositingLayers = frameView.updateCompositingLayersAfterStyleChange();
+
+        if (m_renderView->needsLayout())
+            frameView.scheduleRelayout();
     }
 
     // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
@@ -1854,12 +1858,6 @@
         frameView->layout();
 }
 
-// FIXME: This is a bad idea and needs to be removed eventually.
-// Other browsers load stylesheets before they continue parsing the web page.
-// Since we don't, we can run _javascript_ code that needs answers before the
-// stylesheets are loaded. Doing a layout ignoring the pending stylesheets
-// lets us get reasonable answers. The long term solution to this problem is
-// to instead suspend _javascript_ execution.
 void Document::updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks runPostLayoutTasks)
 {
     bool oldIgnore = m_ignorePendingStylesheets;
@@ -1866,22 +1864,9 @@
 
     if (!haveStylesheetsLoaded()) {
         m_ignorePendingStylesheets = true;
-        // FIXME: We are willing to attempt to suppress painting with outdated style info only once.  Our assumption is that it would be
-        // dangerous to try to stop it a second time, after page content has already been loaded and displayed
-        // with accurate style information.  (Our suppression involves blanking the whole page at the
-        // moment.  If it were more refined, we might be able to do something better.)
-        // It's worth noting though that this entire method is a hack, since what we really want to do is
-        // suspend JS instead of doing a layout with inaccurate information.
-        HTMLElement* bodyElement = bodyOrFrameset();
-        if (bodyElement && !bodyElement->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
-            m_pendingSheetLayout = DidLayoutWithPendingSheets;
-            styleScope().didChangeActiveStyleSheetCandidates();
-            resolveStyle(ResolveStyleType::Rebuild);
-        } else if (m_hasNodesWithPlaceholderStyle)
-            // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes 
-            // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive 
-            // but here we need up-to-date style immediately.
-            resolveStyle(ResolveStyleType::Rebuild);
+        // FIXME: This should just invalidate elements with missing styles.
+        if (m_hasNodesWithMissingStyle)
+            scheduleForcedStyleRecalc();
     }
 
     updateLayout();
@@ -2723,14 +2708,16 @@
 
 bool Document::shouldScheduleLayout()
 {
-    // This function will only be called when FrameView thinks a layout is needed.
-    // This enforces a couple extra rules.
-    //
-    //    (a) Only schedule a layout once the stylesheets are loaded.
-    //    (b) Only schedule layout once we have a body element.
+    if (!documentElement())
+        return false;
+    if (!is<HTMLHtmlElement>(*documentElement()))
+        return true;
+    if (!bodyOrFrameset())
+        return false;
+    if (styleScope().hasPendingSheetsBeforeBody())
+        return false;
 
-    return (haveStylesheetsLoaded() && bodyOrFrameset())
-        || (documentElement() && !is<HTMLHtmlElement>(*documentElement()));
+    return true;
 }
     
 bool Document::isLayoutTimerActive()
@@ -3034,15 +3021,6 @@
 
 void Document::didRemoveAllPendingStylesheet()
 {
-    if (m_pendingSheetLayout == DidLayoutWithPendingSheets) {
-        // Painting is disabled when doing layouts with pending sheets to avoid FOUC.
-        // We need to force paint when coming out from this state.
-        // FIXME: This is not very elegant.
-        m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
-        if (renderView())
-            renderView()->repaintViewAndCompositedLayers();
-    }
-
     if (auto* parser = scriptableDocumentParser())
         parser->executeScriptsWaitingForStylesheetsSoon();
 }

Modified: trunk/Source/WebCore/dom/Document.h (214434 => 214435)


--- trunk/Source/WebCore/dom/Document.h	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/dom/Document.h	2017-03-27 22:56:32 UTC (rev 214435)
@@ -936,13 +936,11 @@
     WEBCORE_EXPORT Ref<XPathNSResolver> createNSResolver(Node* nodeResolver);
     WEBCORE_EXPORT ExceptionOr<Ref<XPathResult>> evaluate(const String& _expression_, Node* contextNode, RefPtr<XPathNSResolver>&&, unsigned short type, XPathResult*);
 
-    enum PendingSheetLayout { NoLayoutWithPendingSheets, DidLayoutWithPendingSheets, IgnoreLayoutWithPendingSheets };
+    bool hasNodesWithNonFinalStyle() const { return m_hasNodesWithNonFinalStyle; }
+    void setHasNodesWithNonFinalStyle() { m_hasNodesWithNonFinalStyle = true; }
+    bool hasNodesWithMissingStyle() const { return m_hasNodesWithMissingStyle; }
+    void setHasNodesWithMissingStyle() { m_hasNodesWithMissingStyle = true; }
 
-    bool didLayoutWithPendingStylesheets() const { return m_pendingSheetLayout == DidLayoutWithPendingSheets; }
-
-    bool hasNodesWithPlaceholderStyle() const { return m_hasNodesWithPlaceholderStyle; }
-    void setHasNodesWithPlaceholderStyle() { m_hasNodesWithPlaceholderStyle = true; }
-
     void updateFocusAppearanceSoon(SelectionRestorationMode);
     void cancelFocusAppearanceUpdate();
 
@@ -1678,16 +1676,12 @@
     bool m_wellFormed { false };
     bool m_createRenderers { true };
 
-    bool m_hasNodesWithPlaceholderStyle { false };
+    bool m_hasNodesWithNonFinalStyle { false };
+    bool m_hasNodesWithMissingStyle { false };
     // But sometimes you need to ignore pending stylesheet count to
     // force an immediate layout when requested by JS.
     bool m_ignorePendingStylesheets { false };
 
-    // If we do ignore the pending stylesheet count, then we need to add a boolean
-    // to track that this happened so that we can do a full repaint when the stylesheets
-    // do eventually load.
-    PendingSheetLayout m_pendingSheetLayout { NoLayoutWithPendingSheets };
-
     bool m_hasElementUsingStyleBasedEditability { false };
     bool m_focusNavigationStartingNodeIsRemoved { false };
 

Modified: trunk/Source/WebCore/html/HTMLFrameSetElement.cpp (214434 => 214435)


--- trunk/Source/WebCore/html/HTMLFrameSetElement.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/html/HTMLFrameSetElement.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -153,7 +153,7 @@
 {
     // For compatibility, frames render even when display: none is set.
     // However, we delay creating a renderer until stylesheets have loaded. 
-    return !style.isPlaceholderStyle();
+    return !style.isNotFinal();
 }
 
 RenderPtr<RenderElement> HTMLFrameSetElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)

Modified: trunk/Source/WebCore/page/FrameView.cpp (214434 => 214435)


--- trunk/Source/WebCore/page/FrameView.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/page/FrameView.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -4586,6 +4586,10 @@
     if (!frame().document()->parsing() && frame().loader().stateMachine().committedFirstRealDocumentLoad())
         return true;
 
+    // FIXME: We should also ignore renderers with non-final style.
+    if (frame().document()->styleScope().hasPendingSheetsBeforeBody())
+        return false;
+
     // Require the document to grow a bit.
     // Using a value of 48 allows the header on Google's search page to render immediately before search results populate later.
     static const int documentHeightThreshold = 48;
@@ -5128,7 +5132,7 @@
     updateIsVisuallyNonEmpty();
 
     // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
-    if (m_isVisuallyNonEmpty && !frame().document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
+    if (m_isVisuallyNonEmpty &&m_firstVisuallyNonEmptyLayoutCallbackPending) {
         m_firstVisuallyNonEmptyLayoutCallbackPending = false;
         if (requestedMilestones & DidFirstVisuallyNonEmptyLayout)
             milestonesAchieved |= DidFirstVisuallyNonEmptyLayout;

Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (214434 => 214435)


--- trunk/Source/WebCore/rendering/RenderBlock.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -1579,10 +1579,10 @@
 
 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
-    // Avoid painting descendants of the root element when stylesheets haven't loaded.  This eliminates FOUC.
-    // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
-    // will do a full repaint.
-    if (document().didLayoutWithPendingStylesheets() && !isRenderView())
+    // Style is non-final if the element has a pending stylesheet before it. We end up with renderers with such styles if a script
+    // forces renderer construction by querying something layout dependent.
+    // Avoid FOUC by not painting. Switching to final style triggers repaint.
+    if (style().isNotFinal())
         return;
 
     if (childrenInline())

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (214434 => 214435)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -3939,10 +3939,7 @@
     
 static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
 {
-    // Avoid painting descendants of the root layer when stylesheets haven't loaded. This eliminates FOUC.
-    // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
-    // will do a full repaint().
-    if (layer->renderer().document().didLayoutWithPendingStylesheets() && !layer->isRootLayer() && !layer->renderer().isDocumentElementRenderer())
+    if (layer->renderer().style().isNotFinal() && !layer->isRootLayer() && !layer->renderer().isDocumentElementRenderer())
         return true;
 
     // Avoid painting all layers if the document is in a state where visual updates aren't allowed.

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.cpp (214434 => 214435)


--- trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -853,6 +853,9 @@
         || m_rareInheritedData->imageRendering != other.m_rareInheritedData->imageRendering)
         return true;
 
+    if (m_rareNonInheritedData->isNotFinal != other.m_rareNonInheritedData->isNotFinal)
+        return true;
+
     if (m_rareNonInheritedData->shapeOutside != other.m_rareNonInheritedData->shapeOutside)
         return true;
 

Modified: trunk/Source/WebCore/rendering/style/RenderStyle.h (214434 => 214435)


--- trunk/Source/WebCore/rendering/style/RenderStyle.h	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/rendering/style/RenderStyle.h	2017-03-27 22:56:32 UTC (rev 214435)
@@ -1659,8 +1659,9 @@
     static Isolation initialIsolation() { return IsolationAuto; }
 #endif
 
-    bool isPlaceholderStyle() const { return m_rareNonInheritedData->isPlaceholderStyle; }
-    void setIsPlaceholderStyle() { SET_VAR(m_rareNonInheritedData, isPlaceholderStyle, true); }
+    // Indicates the style is likely to change due to a pending stylesheet load.
+    bool isNotFinal() const { return m_rareNonInheritedData->isNotFinal; }
+    void setIsNotFinal() { SET_VAR(m_rareNonInheritedData, isNotFinal, true); }
 
     void setVisitedLinkColor(const Color&);
     void setVisitedLinkBackgroundColor(const Color& v) { SET_VAR(m_rareNonInheritedData, visitedLinkBackgroundColor, v); }

Modified: trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp (214434 => 214435)


--- trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -107,7 +107,7 @@
     , breakInside(RenderStyle::initialBreakInside())
     , resize(RenderStyle::initialResize())
     , hasAttrContent(false)
-    , isPlaceholderStyle(false)
+    , isNotFinal(false)
 {
     maskBoxImage.setMaskDefaults();
 }
@@ -200,7 +200,7 @@
     , breakInside(o.breakInside)
     , resize(o.resize)
     , hasAttrContent(o.hasAttrContent)
-    , isPlaceholderStyle(o.isPlaceholderStyle)
+    , isNotFinal(o.isNotFinal)
 {
 }
 
@@ -304,7 +304,7 @@
         && breakInside == o.breakInside
         && resize == o.resize
         && hasAttrContent == o.hasAttrContent
-        && isPlaceholderStyle == o.isPlaceholderStyle;
+        && isNotFinal == o.isNotFinal;
 }
 
 bool StyleRareNonInheritedData::contentDataEquivalent(const StyleRareNonInheritedData& other) const

Modified: trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.h (214434 => 214435)


--- trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.h	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/rendering/style/StyleRareNonInheritedData.h	2017-03-27 22:56:32 UTC (rev 214435)
@@ -220,7 +220,7 @@
 
     unsigned hasAttrContent : 1;
 
-    unsigned isPlaceholderStyle : 1;
+    unsigned isNotFinal : 1;
 
 private:
     StyleRareNonInheritedData();

Modified: trunk/Source/WebCore/style/StyleScope.cpp (214434 => 214435)


--- trunk/Source/WebCore/style/StyleScope.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/style/StyleScope.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -394,7 +394,7 @@
     auto styleResolverUpdateType = hasInsertions ? Reset : Additive;
 
     // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
-    if (!m_document.bodyOrFrameset() || m_document.hasNodesWithPlaceholderStyle())
+    if (!m_document.bodyOrFrameset() || m_document.hasNodesWithNonFinalStyle() || m_document.hasNodesWithMissingStyle())
         return styleResolverUpdateType;
 
     StyleInvalidationAnalysis invalidationAnalysis(addedSheets, styleResolver.mediaQueryEvaluator());
@@ -445,7 +445,7 @@
 
     // Don't bother updating, since we haven't loaded all our style info yet
     // and haven't calculated the style resolver for the first time.
-    if (!m_shadowRoot && !m_didUpdateActiveStyleSheets && hasPendingSheets()) {
+    if (!m_shadowRoot && !m_didUpdateActiveStyleSheets && hasPendingSheetsBeforeBody()) {
         clearResolver();
         return;
     }

Modified: trunk/Source/WebCore/style/StyleTreeResolver.cpp (214434 => 214435)


--- trunk/Source/WebCore/style/StyleTreeResolver.cpp	2017-03-27 22:22:40 UTC (rev 214434)
+++ trunk/Source/WebCore/style/StyleTreeResolver.cpp	2017-03-27 22:56:32 UTC (rev 214435)
@@ -51,24 +51,6 @@
 
 namespace Style {
 
-static std::unique_ptr<RenderStyle> makePlaceholderStyle(Document& document)
-{
-    auto placeholderStyle = RenderStyle::createPtr();
-    placeholderStyle->setDisplay(NONE);
-    placeholderStyle->setIsPlaceholderStyle();
-
-    FontCascadeDescription fontDescription;
-    fontDescription.setOneFamily(standardFamily);
-    fontDescription.setKeywordSizeFromIdentifier(CSSValueMedium);
-    float size = Style::fontSizeForKeyword(CSSValueMedium, false, document);
-    fontDescription.setSpecifiedSize(size);
-    fontDescription.setComputedSize(size);
-    placeholderStyle->setFontDescription(fontDescription);
-
-    placeholderStyle->fontCascade().update(&document.fontSelector());
-    return placeholderStyle;
-}
-
 TreeResolver::TreeResolver(Document& document)
     : m_document(document)
 {
@@ -126,11 +108,6 @@
 
 std::unique_ptr<RenderStyle> TreeResolver::styleForElement(Element& element, const RenderStyle& inheritedStyle)
 {
-    if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
-        m_document.setHasNodesWithPlaceholderStyle();
-        return makePlaceholderStyle(m_document);
-    }
-
     if (element.hasCustomStyleResolveCallbacks()) {
         RenderStyle* shadowHostStyle = scope().shadowRoot ? m_update->elementStyle(*scope().shadowRoot->host()) : nullptr;
         if (auto customStyle = element.resolveCustomStyle(inheritedStyle, shadowHostStyle)) {
@@ -191,15 +168,25 @@
 
 ElementUpdate TreeResolver::resolveElement(Element& element)
 {
+    if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
+        m_document.setHasNodesWithMissingStyle();
+        return { };
+    }
+
     auto newStyle = styleForElement(element, parent().style);
 
     if (!affectsRenderedSubtree(element, *newStyle))
         return { };
 
+    auto* existingStyle = element.renderStyle();
+
+    if (m_didSeePendingStylesheet && (!existingStyle || existingStyle->isNotFinal())) {
+        newStyle->setIsNotFinal();
+        m_document.setHasNodesWithNonFinalStyle();
+    }
+
     auto update = createAnimatedElementUpdate(WTFMove(newStyle), element, parent().change);
 
-    auto* existingStyle = element.renderStyle();
-
     if (&element == m_document.documentElement()) {
         m_documentElementStyle = RenderStyle::clonePtr(*update.style);
         scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to