Revert r213712, caused iPad PLT regression
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Mar 2017 03:20:18 +0000 (03:20 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Mar 2017 03:20:18 +0000 (03:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170040

Unreviewed.

Source/WebCore:

A few subtests have big regressions.

* css/StyleResolver.cpp:
(WebCore::StyleResolver::pseudoStyleRulesForElement):
* dom/Document.cpp:
(WebCore::Document::resolveStyle):
(WebCore::Document::updateLayoutIgnorePendingStylesheets):
(WebCore::Document::shouldScheduleLayout):
(WebCore::Document::didRemoveAllPendingStylesheet):
* dom/Document.h:
(WebCore::Document::didLayoutWithPendingStylesheets):
(WebCore::Document::hasNodesWithPlaceholderStyle):
(WebCore::Document::setHasNodesWithPlaceholderStyle):
(WebCore::Document::hasNodesWithNonFinalStyle): Deleted.
(WebCore::Document::setHasNodesWithNonFinalStyle): Deleted.
* html/HTMLFrameSetElement.cpp:
(WebCore::HTMLFrameSetElement::rendererIsNeeded):
* page/FrameView.cpp:
(WebCore::FrameView::qualifiesAsVisuallyNonEmpty):
(WebCore::FrameView::fireLayoutRelatedMilestonesIfNeeded):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::paintContents):
* rendering/RenderLayer.cpp:
(WebCore::shouldSuppressPaintingLayer):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::changeRequiresRepaint):
* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::isPlaceholderStyle):
(WebCore::RenderStyle::setIsPlaceholderStyle):
(WebCore::RenderStyle::isNotFinal): Deleted.
(WebCore::RenderStyle::setIsNotFinal): Deleted.
* 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::makePlaceholderStyle):
(WebCore::Style::TreeResolver::styleForElement):
(WebCore::Style::TreeResolver::resolveElement):

LayoutTests:

* http/tests/incremental/stylesheet-body-incremental-rendering-expected.html: Removed.
* http/tests/incremental/stylesheet-body-incremental-rendering.html: Removed.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@214333 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering-expected.html [deleted file]
LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering.html [deleted file]
Source/WebCore/ChangeLog
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/html/HTMLFrameSetElement.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp
Source/WebCore/rendering/style/StyleRareNonInheritedData.h
Source/WebCore/style/StyleScope.cpp
Source/WebCore/style/StyleTreeResolver.cpp

index 6773b03..f9682a1 100644 (file)
@@ -1,3 +1,13 @@
+2017-03-23  Antti Koivisto  <antti@apple.com>
+
+        Revert r213712, caused iPad PLT regression
+        https://bugs.webkit.org/show_bug.cgi?id=170040
+
+        Unreviewed.
+
+        * http/tests/incremental/stylesheet-body-incremental-rendering-expected.html: Removed.
+        * http/tests/incremental/stylesheet-body-incremental-rendering.html: Removed.
+
 2017-03-23  Chris Dumez  <cdumez@apple.com>
 
         SVG animations are not paused when their <svg> element is removed from the document
diff --git a/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering-expected.html b/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering-expected.html
deleted file mode 100644 (file)
index a1175e4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<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>
diff --git a/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering.html b/LayoutTests/http/tests/incremental/stylesheet-body-incremental-rendering.html
deleted file mode 100644 (file)
index cc53587..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<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="resources/delayed-css.php?delay=300">
-<div class=delayed style="width:100px; height:100px; background-color:red"></div>
index 7b6baca..23765eb 100644 (file)
@@ -1,3 +1,53 @@
+2017-03-23  Antti Koivisto  <antti@apple.com>
+
+        Revert r213712, caused iPad PLT regression
+        https://bugs.webkit.org/show_bug.cgi?id=170040
+
+        Unreviewed.
+
+        A few subtests have big regressions.
+
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::pseudoStyleRulesForElement):
+        * dom/Document.cpp:
+        (WebCore::Document::resolveStyle):
+        (WebCore::Document::updateLayoutIgnorePendingStylesheets):
+        (WebCore::Document::shouldScheduleLayout):
+        (WebCore::Document::didRemoveAllPendingStylesheet):
+        * dom/Document.h:
+        (WebCore::Document::didLayoutWithPendingStylesheets):
+        (WebCore::Document::hasNodesWithPlaceholderStyle):
+        (WebCore::Document::setHasNodesWithPlaceholderStyle):
+        (WebCore::Document::hasNodesWithNonFinalStyle): Deleted.
+        (WebCore::Document::setHasNodesWithNonFinalStyle): Deleted.
+        * html/HTMLFrameSetElement.cpp:
+        (WebCore::HTMLFrameSetElement::rendererIsNeeded):
+        * page/FrameView.cpp:
+        (WebCore::FrameView::qualifiesAsVisuallyNonEmpty):
+        (WebCore::FrameView::fireLayoutRelatedMilestonesIfNeeded):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::paintContents):
+        * rendering/RenderLayer.cpp:
+        (WebCore::shouldSuppressPaintingLayer):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::changeRequiresRepaint):
+        * rendering/style/RenderStyle.h:
+        (WebCore::RenderStyle::isPlaceholderStyle):
+        (WebCore::RenderStyle::setIsPlaceholderStyle):
+        (WebCore::RenderStyle::isNotFinal): Deleted.
+        (WebCore::RenderStyle::setIsNotFinal): Deleted.
+        * 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::makePlaceholderStyle):
+        (WebCore::Style::TreeResolver::styleForElement):
+        (WebCore::Style::TreeResolver::resolveElement):
+
 2017-03-23  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         Dragging on a large image should not revert to a file icon if data interaction is enabled
index ae7f976..0ace4c2 100644 (file)
@@ -1123,8 +1123,8 @@ Vector<RefPtr<StyleRule>> StyleResolver::styleRulesForElement(const Element* ele
 
 Vector<RefPtr<StyleRule>> StyleResolver::pseudoStyleRulesForElement(const Element* element, PseudoId pseudoId, unsigned rulesToInclude)
 {
-    if (!element)
-        return { };
+    if (!element || !element->document().haveStylesheetsLoaded())
+        return Vector<RefPtr<StyleRule>>();
 
     m_state = State(*element, nullptr);
 
index 38485f4..4b4922b 100644 (file)
@@ -1725,7 +1725,7 @@ void Document::resolveStyle(ResolveStyleType type)
 
         if (type == ResolveStyleType::Rebuild) {
             // This may get set again during style resolve.
-            m_hasNodesWithNonFinalStyle = false;
+            m_hasNodesWithPlaceholderStyle = false;
 
             auto documentStyle = Style::resolveForDocument(*this);
 
@@ -1761,9 +1761,6 @@ void Document::resolveStyle(ResolveStyleType type)
         }
 
         updatedCompositingLayers = frameView.updateCompositingLayersAfterStyleChange();
-
-        if (m_renderView->needsLayout())
-            frameView.scheduleRelayout();
     }
 
     // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
@@ -1857,14 +1854,33 @@ void Document::updateLayout()
         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;
 
     if (!haveStylesheetsLoaded()) {
         m_ignorePendingStylesheets = true;
-        // FIXME: This should just invalidate elements with non-final styles.
-        if (m_hasNodesWithNonFinalStyle)
+        // 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);
     }
 
@@ -2698,16 +2714,14 @@ void Document::setParsing(bool b)
 
 bool Document::shouldScheduleLayout()
 {
-    if (!documentElement())
-        return false;
-    if (!is<HTMLHtmlElement>(*documentElement()))
-        return true;
-    if (!bodyOrFrameset())
-        return false;
-    if (styleScope().hasPendingSheetsBeforeBody())
-        return false;
+    // 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.
 
-    return true;
+    return (haveStylesheetsLoaded() && bodyOrFrameset())
+        || (documentElement() && !is<HTMLHtmlElement>(*documentElement()));
 }
     
 bool Document::isLayoutTimerActive()
@@ -3011,6 +3025,15 @@ Frame* Document::findUnsafeParentScrollPropagationBoundary()
 
 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();
 }
index 85b6ca3..4c938d7 100644 (file)
@@ -936,8 +936,12 @@ public:
     WEBCORE_EXPORT Ref<XPathNSResolver> createNSResolver(Node* nodeResolver);
     WEBCORE_EXPORT ExceptionOr<Ref<XPathResult>> evaluate(const String& expression, Node* contextNode, RefPtr<XPathNSResolver>&&, unsigned short type, XPathResult*);
 
-    bool hasNodesWithNonFinalStyle() const { return m_hasNodesWithNonFinalStyle; }
-    void setHasNodesWithNonFinalStyle() { m_hasNodesWithNonFinalStyle = true; }
+    enum PendingSheetLayout { NoLayoutWithPendingSheets, DidLayoutWithPendingSheets, IgnoreLayoutWithPendingSheets };
+
+    bool didLayoutWithPendingStylesheets() const { return m_pendingSheetLayout == DidLayoutWithPendingSheets; }
+
+    bool hasNodesWithPlaceholderStyle() const { return m_hasNodesWithPlaceholderStyle; }
+    void setHasNodesWithPlaceholderStyle() { m_hasNodesWithPlaceholderStyle = true; }
 
     void updateFocusAppearanceSoon(SelectionRestorationMode);
     void cancelFocusAppearanceUpdate();
@@ -1674,11 +1678,16 @@ private:
     bool m_wellFormed { false };
     bool m_createRenderers { true };
 
-    bool m_hasNodesWithNonFinalStyle { false };
+    bool m_hasNodesWithPlaceholderStyle { 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 };
 
index 2a6477a..01c5d1f 100644 (file)
@@ -153,7 +153,7 @@ bool HTMLFrameSetElement::rendererIsNeeded(const RenderStyle& style)
 {
     // For compatibility, frames render even when display: none is set.
     // However, we delay creating a renderer until stylesheets have loaded. 
-    return !style.isNotFinal();
+    return !style.isPlaceholderStyle();
 }
 
 RenderPtr<RenderElement> HTMLFrameSetElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
index aa0b347..aefa99f 100644 (file)
@@ -4586,10 +4586,6 @@ bool FrameView::qualifiesAsVisuallyNonEmpty() const
     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;
@@ -5132,7 +5128,7 @@ void FrameView::fireLayoutRelatedMilestonesIfNeeded()
     updateIsVisuallyNonEmpty();
 
     // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
-    if (m_isVisuallyNonEmpty &&m_firstVisuallyNonEmptyLayoutCallbackPending) {
+    if (m_isVisuallyNonEmpty && !frame().document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
         m_firstVisuallyNonEmptyLayoutCallbackPending = false;
         if (requestedMilestones & DidFirstVisuallyNonEmptyLayout)
             milestonesAchieved |= DidFirstVisuallyNonEmptyLayout;
index 76cddf9..8922a04 100644 (file)
@@ -1579,10 +1579,10 @@ void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 
 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
-    // 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())
+    // 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())
         return;
 
     if (childrenInline())
index b73295f..efbc3b4 100644 (file)
@@ -3939,7 +3939,10 @@ static inline bool shouldDoSoftwarePaint(const RenderLayer* layer, bool painting
     
 static inline bool shouldSuppressPaintingLayer(RenderLayer* layer)
 {
-    if (layer->renderer().style().isNotFinal() && !layer->isRootLayer() && !layer->renderer().isDocumentElementRenderer())
+    // 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())
         return true;
 
     // Avoid painting all layers if the document is in a state where visual updates aren't allowed.
index 870f28a..0addd0a 100644 (file)
@@ -853,9 +853,6 @@ bool RenderStyle::changeRequiresRepaint(const RenderStyle& other, unsigned& chan
         || 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;
 
index 278adf5..2219d9e 100644 (file)
@@ -1653,9 +1653,8 @@ public:
     static Isolation initialIsolation() { return IsolationAuto; }
 #endif
 
-    // 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); }
+    bool isPlaceholderStyle() const { return m_rareNonInheritedData->isPlaceholderStyle; }
+    void setIsPlaceholderStyle() { SET_VAR(m_rareNonInheritedData, isPlaceholderStyle, true); }
 
     void setVisitedLinkColor(const Color&);
     void setVisitedLinkBackgroundColor(const Color& v) { SET_VAR(m_rareNonInheritedData, visitedLinkBackgroundColor, v); }
index 8776b33..3b48888 100644 (file)
@@ -107,7 +107,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData()
     , breakInside(RenderStyle::initialBreakInside())
     , resize(RenderStyle::initialResize())
     , hasAttrContent(false)
-    , isNotFinal(false)
+    , isPlaceholderStyle(false)
 {
     maskBoxImage.setMaskDefaults();
 }
@@ -200,7 +200,7 @@ inline StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonIn
     , breakInside(o.breakInside)
     , resize(o.resize)
     , hasAttrContent(o.hasAttrContent)
-    , isNotFinal(o.isNotFinal)
+    , isPlaceholderStyle(o.isPlaceholderStyle)
 {
 }
 
@@ -304,7 +304,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c
         && breakInside == o.breakInside
         && resize == o.resize
         && hasAttrContent == o.hasAttrContent
-        && isNotFinal == o.isNotFinal;
+        && isPlaceholderStyle == o.isPlaceholderStyle;
 }
 
 bool StyleRareNonInheritedData::contentDataEquivalent(const StyleRareNonInheritedData& other) const
index 6981db6..b58abae 100644 (file)
@@ -220,7 +220,7 @@ public:
 
     unsigned hasAttrContent : 1;
 
-    unsigned isNotFinal : 1;
+    unsigned isPlaceholderStyle : 1;
 
 private:
     StyleRareNonInheritedData();
index 14e881c..02f4d44 100644 (file)
@@ -389,7 +389,7 @@ Scope::StyleResolverUpdateType Scope::analyzeStyleSheetChange(const Vector<RefPt
     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.hasNodesWithNonFinalStyle())
+    if (!m_document.bodyOrFrameset() || m_document.hasNodesWithPlaceholderStyle())
         return styleResolverUpdateType;
 
     StyleInvalidationAnalysis invalidationAnalysis(addedSheets, styleResolver.mediaQueryEvaluator());
@@ -440,7 +440,7 @@ void Scope::updateActiveStyleSheets(UpdateType updateType)
 
     // 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 && hasPendingSheetsBeforeBody()) {
+    if (!m_shadowRoot && !m_didUpdateActiveStyleSheets && hasPendingSheets()) {
         clearResolver();
         return;
     }
index 102457f..30003fb 100644 (file)
@@ -51,6 +51,24 @@ namespace WebCore {
 
 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)
 {
@@ -108,6 +126,11 @@ void TreeResolver::popScope()
 
 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)) {
@@ -168,25 +191,15 @@ static bool affectsRenderedSubtree(Element& element, const RenderStyle& newStyle
 
 ElementUpdate TreeResolver::resolveElement(Element& element)
 {
-    if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
-        m_document.setHasNodesWithNonFinalStyle();
-        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());