Changeset 213446 in webkit


Ignore:
Timestamp:
Mar 6, 2017 4:19:43 AM (7 years ago)
Author:
Antti Koivisto
Message:

Allow render tree building before loading stylesheet elements
https://bugs.webkit.org/show_bug.cgi?id=169079
Source/WebCore:

<rdar://problem/30865709>

Reviewed by Andreas Kling.

Currently we don't resolve style or construct renderers if there are any pending
stylesheet loads. This patch enables style and renderer constuction up to the
first encountered loading style element.

This is a step toward allowing incremental rendering for in-body stylesheets.

  • dom/Document.cpp:

(WebCore::Document::needsStyleRecalc):

Ensure scrolling to anchor eventually happens.

  • dom/Document.h:

(WebCore::Document::isIgnoringPendingStylesheets):

  • dom/InlineStyleSheetOwner.cpp:

(WebCore::InlineStyleSheetOwner::createSheet):
(WebCore::InlineStyleSheetOwner::sheetLoaded):
(WebCore::InlineStyleSheetOwner::startLoadingDynamicSheet):

  • dom/ProcessingInstruction.cpp:

(WebCore::ProcessingInstruction::checkStyleSheet):
(WebCore::ProcessingInstruction::sheetLoaded):
(WebCore::ProcessingInstruction::removedFrom):

  • html/HTMLLinkElement.cpp:

(WebCore::HTMLLinkElement::addPendingSheet):
(WebCore::HTMLLinkElement::removePendingSheet):

  • style/StyleScope.cpp:

(WebCore::Style::Scope::addPendingSheet):
(WebCore::Style::Scope::removePendingSheet):

Track pending sheet nodes in a map so we can test if a given node has a pending sheet.
This is also more robust in general.

(WebCore::Style::Scope::hasProcessingInstructionWithPendingSheet):
(WebCore::Style::Scope::updateActiveStyleSheets):

  • style/StyleScope.h:

(WebCore::Style::Scope::hasPendingSheet):
(WebCore::Style::Scope::hasPendingSheets):
(WebCore::Style::Scope::addPendingSheet): Deleted.

  • style/StyleTreeResolver.cpp:

(WebCore::Style::TreeResolver::styleForElement):

Instead of global test for placeholder construction check the status of the pending sheet flag.

(WebCore::Style::hasLoadingStylesheet):
(WebCore::Style::TreeResolver::resolveComposedTree):

Set a flag when encountering a pending top level sheet during DOM traversal.

(WebCore::Style::TreeResolver::resolve):

  • style/StyleTreeResolver.h:
  • svg/graphics/SVGImage.cpp:

(WebCore::SVGImage::dataChanged):

Ensure SVG images have layout before getting the size.

LayoutTests:

Reviewed by Andreas Kling.

Ensure that style is synchronized after adding a stylesheet dynamically by doing an additional test.
Otherwise the class/attr invalidation test may as we don't know about the new stylesheet yet.
This is functionally fine (future synchronization would invalidate the style) but messes up the test
trying to verify class/attr change invalidation specifically.

  • fast/css/style-invalidation-attribute-change-descendants-expected.txt:
  • fast/css/style-invalidation-attribute-change-descendants.html:
  • fast/css/style-invalidation-class-change-descendants-expected.txt:
  • fast/css/style-invalidation-class-change-descendants.html:
Location:
trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r213443 r213446  
     12017-03-06  Antti Koivisto  <antti@apple.com>
     2
     3        Allow render tree building before loading stylesheet elements
     4        https://bugs.webkit.org/show_bug.cgi?id=169079
     5
     6        Reviewed by Andreas Kling.
     7
     8        Ensure that style is synchronized after adding a stylesheet dynamically by doing an additional test.
     9        Otherwise the class/attr invalidation test may as we don't know about the new stylesheet yet.
     10        This is functionally fine (future synchronization would invalidate the style) but messes up the test
     11        trying to verify class/attr change invalidation specifically.
     12
     13        * fast/css/style-invalidation-attribute-change-descendants-expected.txt:
     14        * fast/css/style-invalidation-attribute-change-descendants.html:
     15        * fast/css/style-invalidation-class-change-descendants-expected.txt:
     16        * fast/css/style-invalidation-class-change-descendants.html:
     17
    1182017-03-05  Carlos Garcia Campos  <cgarcia@igalia.com>
    219
  • trunk/LayoutTests/fast/css/style-invalidation-attribute-change-descendants-expected.txt

    r202104 r213446  
    171171PASS hasExpectedStyle is true
    172172Inserting stylesheet '[myattr3] target { color:rgb(12, 0, 0); }'
     173PASS testStyleChangeType("root", "NoStyleChange") || testStyleChangeType("root", "InlineStyleChange") is true
     174PASS testStyleChangeType("target", "NoStyleChange") is true
     175PASS testStyleChangeType("inert", "NoStyleChange") is true
     176PASS hasExpectedStyle is true
    173177Setting attribute 'myattr3' value ''
    174178PASS testStyleChangeType("root", "NoStyleChange") || testStyleChangeType("root", "InlineStyleChange") is true
  • trunk/LayoutTests/fast/css/style-invalidation-attribute-change-descendants.html

    r202104 r213446  
    277277document.head.appendChild(dynamicSheet);
    278278
     279testStyleInvalidation("NoStyleChange");
     280checkStyle(11);
     281
    279282setAttribute('myattr3', '');
    280283testStyleInvalidation("InlineStyleChange");
  • trunk/LayoutTests/fast/css/style-invalidation-class-change-descendants-expected.txt

    r202104 r213446  
    7474PASS hasExpectedStyle is true
    7575Inserting stylesheet 'root.dynamicStyle target { color:rgb(6, 6, 6); }'
     76PASS testStyleChangeType("root", "NoStyleChange") || testStyleChangeType("root", "InlineStyleChange") is true
     77PASS testStyleChangeType("target", "NoStyleChange") is true
     78PASS testStyleChangeType("inert", "NoStyleChange") is true
     79PASS hasExpectedStyle is true
    7680Adding class dynamicStyle
    7781PASS testStyleChangeType("root", "NoStyleChange") || testStyleChangeType("root", "InlineStyleChange") is true
  • trunk/LayoutTests/fast/css/style-invalidation-class-change-descendants.html

    r202104 r213446  
    168168removeClass('dynamicStyle');
    169169testStyleInvalidation("NoStyleChange");
    170 checkStyle(0)
     170checkStyle(0);
    171171
    172172var dynamicSheet = document.createElement("style");
     
    174174debug("Inserting stylesheet '" + dynamicSheet.innerHTML + "'");
    175175document.head.appendChild(dynamicSheet);
     176
     177testStyleInvalidation("NoStyleChange");
     178checkStyle(0);
    176179
    177180addClass('dynamicStyle');
  • trunk/Source/WebCore/ChangeLog

    r213445 r213446  
     12017-03-06  Antti Koivisto  <antti@apple.com>
     2
     3        Allow render tree building before loading stylesheet elements
     4        https://bugs.webkit.org/show_bug.cgi?id=169079
     5        <rdar://problem/30865709>
     6
     7        Reviewed by Andreas Kling.
     8
     9        Currently we don't resolve style or construct renderers if there are any pending
     10        stylesheet loads. This patch enables style and renderer constuction up to the
     11        first encountered loading style element.
     12
     13        This is a step toward allowing incremental rendering for in-body stylesheets.
     14
     15        * dom/Document.cpp:
     16        (WebCore::Document::needsStyleRecalc):
     17
     18            Ensure scrolling to anchor eventually happens.
     19
     20        * dom/Document.h:
     21        (WebCore::Document::isIgnoringPendingStylesheets):
     22        * dom/InlineStyleSheetOwner.cpp:
     23        (WebCore::InlineStyleSheetOwner::createSheet):
     24        (WebCore::InlineStyleSheetOwner::sheetLoaded):
     25        (WebCore::InlineStyleSheetOwner::startLoadingDynamicSheet):
     26        * dom/ProcessingInstruction.cpp:
     27        (WebCore::ProcessingInstruction::checkStyleSheet):
     28        (WebCore::ProcessingInstruction::sheetLoaded):
     29        (WebCore::ProcessingInstruction::removedFrom):
     30        * html/HTMLLinkElement.cpp:
     31        (WebCore::HTMLLinkElement::addPendingSheet):
     32        (WebCore::HTMLLinkElement::removePendingSheet):
     33        * style/StyleScope.cpp:
     34        (WebCore::Style::Scope::addPendingSheet):
     35        (WebCore::Style::Scope::removePendingSheet):
     36
     37            Track pending sheet nodes in a map so we can test if a given node has a pending sheet.
     38            This is also more robust in general.
     39
     40        (WebCore::Style::Scope::hasProcessingInstructionWithPendingSheet):
     41        (WebCore::Style::Scope::updateActiveStyleSheets):
     42        * style/StyleScope.h:
     43        (WebCore::Style::Scope::hasPendingSheet):
     44        (WebCore::Style::Scope::hasPendingSheets):
     45        (WebCore::Style::Scope::addPendingSheet): Deleted.
     46        * style/StyleTreeResolver.cpp:
     47        (WebCore::Style::TreeResolver::styleForElement):
     48
     49            Instead of global test for placeholder construction check the status of the pending sheet flag.
     50
     51        (WebCore::Style::hasLoadingStylesheet):
     52        (WebCore::Style::TreeResolver::resolveComposedTree):
     53
     54            Set a flag when encountering a pending top level sheet during DOM traversal.
     55
     56        (WebCore::Style::TreeResolver::resolve):
     57        * style/StyleTreeResolver.h:
     58        * svg/graphics/SVGImage.cpp:
     59        (WebCore::SVGImage::dataChanged):
     60
     61            Ensure SVG images have layout before getting the size.
     62
    1632017-03-06  Vanessa Chipirrás Navalón  <vchipirras@igalia.com>
    264
  • trunk/Source/WebCore/dom/Document.cpp

    r213355 r213446  
    18551855        return false;
    18561856
    1857     return m_pendingStyleRecalcShouldForce || childNeedsStyleRecalc() || styleScope().hasPendingUpdate();
     1857    if (m_pendingStyleRecalcShouldForce)
     1858        return true;
     1859
     1860    if (childNeedsStyleRecalc())
     1861        return true;
     1862
     1863    if (styleScope().hasPendingUpdate())
     1864        return true;
     1865
     1866    // Ensure this happens eventually as it is currently in resolveStyle. This can be removed if the code moves.
     1867    if (m_gotoAnchorNeededAfterStylesheetsLoad && !styleScope().hasPendingSheets())
     1868        return true;
     1869
     1870    return false;
    18581871}
    18591872
  • trunk/Source/WebCore/dom/Document.h

    r213266 r213446  
    485485
    486486    WEBCORE_EXPORT bool haveStylesheetsLoaded() const;
     487    bool isIgnoringPendingStylesheets() const { return m_ignorePendingStylesheets; }
    487488
    488489    WEBCORE_EXPORT StyleSheetList& styleSheets();
  • trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp

    r211591 r213446  
    158158    if (m_sheet) {
    159159        if (m_sheet->isLoading() && m_styleScope)
    160             m_styleScope->removePendingSheet();
     160            m_styleScope->removePendingSheet(element);
    161161        clearSheet();
    162162    }
     
    179179
    180180    if (m_styleScope)
    181         m_styleScope->addPendingSheet();
     181        m_styleScope->addPendingSheet(element);
    182182
    183183    auto cacheKey = makeInlineStyleSheetCacheKey(text, element);
     
    229229}
    230230
    231 bool InlineStyleSheetOwner::sheetLoaded(Element&)
     231bool InlineStyleSheetOwner::sheetLoaded(Element& element)
    232232{
    233233    if (isLoading())
     
    235235
    236236    if (m_styleScope)
    237         m_styleScope->removePendingSheet();
     237        m_styleScope->removePendingSheet(element);
    238238
    239239    return true;
    240240}
    241241
    242 void InlineStyleSheetOwner::startLoadingDynamicSheet(Element&)
     242void InlineStyleSheetOwner::startLoadingDynamicSheet(Element& element)
    243243{
    244244    if (m_styleScope)
    245         m_styleScope->addPendingSheet();
     245        m_styleScope->addPendingSheet(element);
    246246}
    247247
  • trunk/Source/WebCore/dom/ProcessingInstruction.cpp

    r211591 r213446  
    130130            }
    131131
     132            if (m_loading) {
     133                m_loading = false;
     134                document().styleScope().removePendingSheet(*this);
     135            }
     136
    132137            String url = document().completeURL(href).string();
    133138            if (!dispatchBeforeLoadEvent(url))
     
    135140
    136141            m_loading = true;
    137             document().styleScope().addPendingSheet();
     142            document().styleScope().addPendingSheet(*this);
    138143
    139144#if ENABLE(XSLT)
     
    155160                // The request may have been denied if (for example) the stylesheet is local and the document is remote.
    156161                m_loading = false;
    157                 document().styleScope().removePendingSheet();
     162                document().styleScope().removePendingSheet(*this);
    158163#if ENABLE(XSLT)
    159164                if (m_isXSL)
     
    177182{
    178183    if (!isLoading()) {
    179         document().styleScope().removePendingSheet();
     184        document().styleScope().removePendingSheet(*this);
    180185#if ENABLE(XSLT)
    181186        if (m_isXSL)
     
    277282    if (m_loading) {
    278283        m_loading = false;
    279         document().styleScope().removePendingSheet();
     284        document().styleScope().removePendingSheet(*this);
    280285    }
    281286
  • trunk/Source/WebCore/html/HTMLLinkElement.cpp

    r212614 r213446  
    552552        return;
    553553    ASSERT(m_styleScope);
    554     m_styleScope->addPendingSheet();
     554    m_styleScope->addPendingSheet(*this);
    555555}
    556556
     
    570570    }
    571571
    572     m_styleScope->removePendingSheet();
     572    m_styleScope->removePendingSheet(*this);
    573573}
    574574
  • trunk/Source/WebCore/style/StyleScope.cpp

    r212828 r213446  
    7373Scope::~Scope()
    7474{
     75    ASSERT(m_nodesWithPendingSheets.isEmpty());
    7576}
    7677
     
    172173}
    173174
     175void Scope::addPendingSheet(const Node& node)
     176{
     177    ASSERT(!m_nodesWithPendingSheets.contains(&node));
     178
     179    m_nodesWithPendingSheets.add(&node);
     180}
     181
    174182// This method is called whenever a top-level stylesheet has finished loading.
    175 void Scope::removePendingSheet()
    176 {
    177     // Make sure we knew this sheet was pending, and that our count isn't out of sync.
    178     ASSERT(m_pendingStyleSheetCount > 0);
    179 
    180     m_pendingStyleSheetCount--;
    181     if (m_pendingStyleSheetCount)
     183void Scope::removePendingSheet(const Node& node)
     184{
     185    ASSERT(m_nodesWithPendingSheets.contains(&node));
     186
     187    m_nodesWithPendingSheets.remove(&node);
     188    if (!m_nodesWithPendingSheets.isEmpty())
    182189        return;
    183190
     
    186193    if (!m_shadowRoot)
    187194        m_document.didRemoveAllPendingStylesheet();
     195}
     196
     197bool Scope::hasProcessingInstructionWithPendingSheet()
     198{
     199    ASSERT(!m_shadowRoot);
     200
     201    for (auto* child = m_document.firstChild(); child; child = child->nextSibling()) {
     202        if (is<Element>(*child))
     203            return false;
     204        if (m_nodesWithPendingSheets.contains(child)) {
     205            ASSERT(is<ProcessingInstruction>(*child));
     206            return true;
     207        }
     208    }
     209    return false;
    188210}
    189211
     
    395417    // Don't bother updating, since we haven't loaded all our style info yet
    396418    // and haven't calculated the style resolver for the first time.
    397     if (!m_shadowRoot && !m_didUpdateActiveStyleSheets && m_pendingStyleSheetCount) {
     419    if (!m_shadowRoot && !m_didUpdateActiveStyleSheets && hasPendingSheets()) {
    398420        clearResolver();
    399421        return;
  • trunk/Source/WebCore/style/StyleScope.h

    r212828 r213446  
    3232#include <wtf/FastMalloc.h>
    3333#include <wtf/HashMap.h>
     34#include <wtf/HashSet.h>
    3435#include <wtf/ListHashSet.h>
    3536#include <wtf/RefPtr.h>
     
    8283    void setSelectedStylesheetSetName(const String&);
    8384
    84     void addPendingSheet() { m_pendingStyleSheetCount++; }
    85     void removePendingSheet();
    86 
    87     bool hasPendingSheets() const { return m_pendingStyleSheetCount > 0; }
     85    void addPendingSheet(const Node&);
     86    void removePendingSheet(const Node&);
     87    bool hasPendingSheet(const Node& node) const { return m_nodesWithPendingSheets.contains(&node); }
     88    bool hasProcessingInstructionWithPendingSheet();
     89    bool hasPendingSheets() const { return !m_nodesWithPendingSheets.isEmpty(); }
    8890
    8991    bool usesStyleBasedEditability() { return m_usesStyleBasedEditability; }
     
    142144    Vector<RefPtr<CSSStyleSheet>> m_activeStyleSheets;
    143145
     146
    144147    Timer m_pendingUpdateTimer;
    145148
    146149    mutable std::unique_ptr<HashSet<const CSSStyleSheet*>> m_weakCopyOfActiveStyleSheetListForFastLookup;
    147150
    148     // Track the number of currently loading top-level stylesheets needed for rendering.
     151    // Track the currently loading top-level stylesheets needed for rendering.
    149152    // Sheets loaded using the @import directive are not included in this count.
    150153    // We use this count of pending sheets to detect when we can begin attaching
    151154    // elements and when it is safe to execute scripts.
    152     int m_pendingStyleSheetCount { 0 };
     155    HashSet<const Node*> m_nodesWithPendingSheets;
     156
    153157    bool m_didUpdateActiveStyleSheets { false };
    154158
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r213266 r213446  
    127127std::unique_ptr<RenderStyle> TreeResolver::styleForElement(Element& element, const RenderStyle& inheritedStyle)
    128128{
    129     if (!m_document.haveStylesheetsLoaded() && !element.renderer()) {
     129    if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
    130130        m_document.setHasNodesWithPlaceholderStyle();
    131131        return makePlaceholderStyle(m_document);
     
    360360}
    361361
     362static bool hasLoadingStylesheet(const Style::Scope& styleScope, const Element& element, bool checkDescendants)
     363{
     364    if (!styleScope.hasPendingSheets())
     365        return false;
     366    if (styleScope.hasPendingSheet(element))
     367        return true;
     368    if (!checkDescendants)
     369        return false;
     370    for (auto& descendant : descendantsOfType<Element>(element)) {
     371        if (styleScope.hasPendingSheet(descendant))
     372            return true;
     373    };
     374    return false;
     375}
     376
    362377void TreeResolver::resolveComposedTree()
    363378{
     
    439454
    440455        bool shouldIterateChildren = style && (element.childNeedsStyleRecalc() || change != NoChange);
     456
     457        if (!m_didSeePendingStylesheet)
     458            m_didSeePendingStylesheet = hasLoadingStylesheet(m_document.styleScope(), element, !shouldIterateChildren);
     459
    441460        if (!shouldIterateChildren) {
    442461            it.traverseNextSkippingChildren();
     
    463482    if (!documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
    464483        return nullptr;
     484
     485    m_didSeePendingStylesheet = m_document.styleScope().hasProcessingInstructionWithPendingSheet();
    465486
    466487    m_update = std::make_unique<Update>(m_document);
  • trunk/Source/WebCore/style/StyleTreeResolver.h

    r213266 r213446  
    103103    Vector<Ref<Scope>, 4> m_scopeStack;
    104104    Vector<Parent, 32> m_parentStack;
     105    bool m_didSeePendingStylesheet { false };
    105106
    106107    std::unique_ptr<Update> m_update;
  • trunk/Source/WebCore/svg/graphics/SVGImage.cpp

    r211161 r213446  
    452452        loader.activeDocumentLoader()->writer().end();
    453453
     454        frame.document()->updateLayoutIgnorePendingStylesheets();
     455
    454456        // Set the intrinsic size before a container size is available.
    455457        m_intrinsicSize = containerSize();
Note: See TracChangeset for help on using the changeset viewer.