Changeset 201799 in webkit


Ignore:
Timestamp:
Jun 8, 2016 1:00:22 AM (8 years ago)
Author:
mmaxfield@apple.com
Message:

Extend CSSFontSelector's lifetime to be longer than the Document's lifetime
https://bugs.webkit.org/show_bug.cgi?id=154101

Reviewed by Darin Adler.

Rather than destroying the Document's CSSFontSelector, instead, the object should
live for the lifetime of the document, and it should instead be asked to clear its
contents.

This is important for the CSS Font Loading API, where the identity of objects the
CSSFontSelector references needs to persist throughout the lifetime of the
Document. This patch represents the first step to implementing this correctly.
The second step is for the CSSFontSelector to perform a diff instead of a
wholesale clear of its contents. Once this is done, font loading objects can
survive through a call to Document::clearStyleResolver().

This patch gives the CSSFontSelector two states: building underway and building not
underway. The state is building underway in between calls to clearStyleResolver()
and when the style resolver gets built back up. Otherwise, the state is building
not underway. Because of this new design, creation of all FontFace objects can be
postponed until a state transition from building underway to building not underway.
A subsequent patch will perform the diff at this point. An ASSERT() makes sure that
we never service a font lookup request while Building.

No new tests because there is no behavior change.

  • css/CSSFontFaceSet.cpp:

(WebCore::CSSFontFaceSet::clear):

  • css/CSSFontSelector.cpp:

(WebCore::CSSFontSelector::buildStarted):
(WebCore::CSSFontSelector::buildCompleted):
(WebCore::CSSFontSelector::addFontFaceRule):
(WebCore::CSSFontSelector::fontRangesForFamily):
(WebCore::CSSFontSelector::CSSFontSelector): Deleted.
(WebCore::CSSFontSelector::clearDocument): Deleted.

  • css/CSSFontSelector.h:
  • css/StyleResolver.cpp:

(WebCore::StyleResolver::appendAuthorStyleSheets):

  • dom/Document.cpp:

(WebCore::Document::Document):
(WebCore::Document::~Document):
(WebCore::Document::clearStyleResolver):
(WebCore::Document::fontSelector): Deleted.

  • dom/Document.h:

(WebCore::Document::fontSelector):

Location:
trunk/Source/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r201798 r201799  
     12016-06-08  Myles C. Maxfield  <mmaxfield@apple.com>
     2
     3        Extend CSSFontSelector's lifetime to be longer than the Document's lifetime
     4        https://bugs.webkit.org/show_bug.cgi?id=154101
     5
     6        Reviewed by Darin Adler.
     7
     8        Rather than destroying the Document's CSSFontSelector, instead, the object should
     9        live for the lifetime of the document, and it should instead be asked to clear its
     10        contents.
     11
     12        This is important for the CSS Font Loading API, where the identity of objects the
     13        CSSFontSelector references needs to persist throughout the lifetime of the
     14        Document. This patch represents the first step to implementing this correctly.
     15        The second step is for the CSSFontSelector to perform a diff instead of a
     16        wholesale clear of its contents. Once this is done, font loading objects can
     17        survive through a call to Document::clearStyleResolver().
     18
     19        This patch gives the CSSFontSelector two states: building underway and building not
     20        underway. The state is building underway in between calls to clearStyleResolver()
     21        and when the style resolver gets built back up. Otherwise, the state is building
     22        not underway. Because of this new design, creation of all FontFace objects can be
     23        postponed until a state transition from building underway to building not underway.
     24        A subsequent patch will perform the diff at this point. An ASSERT() makes sure that
     25        we never service a font lookup request while Building.
     26
     27        No new tests because there is no behavior change.
     28
     29        * css/CSSFontFaceSet.cpp:
     30        (WebCore::CSSFontFaceSet::clear):
     31        * css/CSSFontSelector.cpp:
     32        (WebCore::CSSFontSelector::buildStarted):
     33        (WebCore::CSSFontSelector::buildCompleted):
     34        (WebCore::CSSFontSelector::addFontFaceRule):
     35        (WebCore::CSSFontSelector::fontRangesForFamily):
     36        (WebCore::CSSFontSelector::CSSFontSelector): Deleted.
     37        (WebCore::CSSFontSelector::clearDocument): Deleted.
     38        * css/CSSFontSelector.h:
     39        * css/StyleResolver.cpp:
     40        (WebCore::StyleResolver::appendAuthorStyleSheets):
     41        * dom/Document.cpp:
     42        (WebCore::Document::Document):
     43        (WebCore::Document::~Document):
     44        (WebCore::Document::clearStyleResolver):
     45        (WebCore::Document::fontSelector): Deleted.
     46        * dom/Document.h:
     47        (WebCore::Document::fontSelector):
     48
    1492016-06-08  Adam Bergkvist  <adam.bergkvist@ericsson.com>
    250
  • trunk/Source/WebCore/css/CSSFontFaceSet.cpp

    r201290 r201799  
    245245    m_locallyInstalledFacesLookupTable.clear();
    246246    m_cache.clear();
     247    m_facesPartitionIndex = 0;
     248    m_status = Status::Loaded;
    247249}
    248250
  • trunk/Source/WebCore/css/CSSFontSelector.cpp

    r201596 r201799  
    7272    , m_version(0)
    7373{
    74     // FIXME: An old comment used to say there was no need to hold a reference to m_document
    75     // because "we are guaranteed to be destroyed before the document". But there does not
    76     // seem to be any such guarantee.
    77 
    7874    ASSERT(m_document);
    7975    FontCache::singleton().addClient(*this);
     
    10399}
    104100
     101void CSSFontSelector::buildStarted()
     102{
     103    m_buildIsUnderway = true;
     104    ++m_version;
     105}
     106
     107void CSSFontSelector::buildCompleted()
     108{
     109    if (!m_buildIsUnderway)
     110        return;
     111
     112    m_buildIsUnderway = false;
     113
     114    m_cssFontFaceSet->clear();
     115
     116    for (auto& item : m_stagingArea)
     117        addFontFaceRule(item.styleRuleFontFace, item.isInitiatingElementInUserAgentShadowTree);
     118    m_stagingArea.clear();
     119}
     120
    105121void CSSFontSelector::addFontFaceRule(StyleRuleFontFace& fontFaceRule, bool isInitiatingElementInUserAgentShadowTree)
    106122{
     123    if (m_buildIsUnderway) {
     124        m_stagingArea.append({fontFaceRule, isInitiatingElementInUserAgentShadowTree});
     125        return;
     126    }
     127
    107128    const StyleProperties& style = fontFaceRule.properties();
    108129    RefPtr<CSSValue> fontFamily = style.getPropertyCSSValue(CSSPropertyFontFamily);
     
    236257FontRanges CSSFontSelector::fontRangesForFamily(const FontDescription& fontDescription, const AtomicString& familyName)
    237258{
     259    ASSERT(!m_buildIsUnderway); // If this ASSERT() fires, it usually means you forgot a document.updateStyleIfNeeded() somewhere.
     260
    238261    // FIXME: The spec (and Firefox) says user specified generic families (sans-serif etc.) should be resolved before the @font-face lookup too.
    239262    bool resolveGenericFamilyFirst = familyName == standardFamily;
     
    269292    m_document = nullptr;
    270293
    271     // FIXME: This object should outlive the Document.
    272294    m_cssFontFaceSet->clear();
    273295    m_clients.clear();
  • trunk/Source/WebCore/css/CSSFontSelector.h

    r201596 r201799  
    6666
    6767    void clearDocument();
     68    void buildStarted();
     69    void buildCompleted();
    6870
    6971    void addFontFaceRule(StyleRuleFontFace&, bool isInitiatingElementInUserAgentShadowTree);
     
    9294    void beginLoadTimerFired();
    9395
     96    struct PendingFontFaceRule {
     97        StyleRuleFontFace& styleRuleFontFace;
     98        bool isInitiatingElementInUserAgentShadowTree;
     99    };
     100    Vector<PendingFontFaceRule> m_stagingArea;
     101
    94102    Document* m_document;
    95103    RefPtr<FontFaceSet> m_fontFaceSet;
     
    103111    unsigned m_version;
    104112    bool m_creatingFont { false };
     113    bool m_buildIsUnderway { false };
    105114};
    106115
  • trunk/Source/WebCore/css/SourceSizeList.cpp

    r201441 r201799  
    4848        if (!primitiveValue.isLength())
    4949            return defaultLength(style, renderer);
     50
     51        // Because we evaluate "sizes" at parse time (before style has been resolved), the font metrics used for these specific units
     52        // are not available. The font selector's internal consistency isn't guaranteed just yet, so we can just temporarily clear
     53        // the pointer to it for the duration of the unit evaluation. This is acceptible because the style always comes from the
     54        // RenderView, which has its font information hardcoded in resolveForDocument() to be -webkit-standard, whose operations
     55        // don't require a font selector.
     56        if (!primitiveValue.isCalculated() && (primitiveValue.primitiveType() == CSSPrimitiveValue::CSS_EXS || primitiveValue.primitiveType() == CSSPrimitiveValue::CSS_CHS)) {
     57            RefPtr<FontSelector> fontSelector = style.fontCascade().fontSelector();
     58            style.fontCascade().update(nullptr);
     59            float result = primitiveValue.computeLength<float>(conversionData);
     60            style.fontCascade().update(fontSelector.get());
     61            return result;
     62        }
     63
    5064        return primitiveValue.computeLength<float>(conversionData);
    5165    }
  • trunk/Source/WebCore/css/StyleResolver.cpp

    r201498 r201799  
    297297{
    298298    m_ruleSets.appendAuthorStyleSheets(styleSheets, &m_mediaQueryEvaluator, m_inspectorCSSOMWrappers, this);
     299
     300    document().fontSelector().buildCompleted();
     301
    299302    if (auto renderView = document().renderView())
    300303        renderView->style().fontCascade().update(&document().fontSelector());
  • trunk/Source/WebCore/dom/Document.cpp

    r201782 r201799  
    530530#endif
    531531    , m_templateDocumentHost(nullptr)
     532    , m_fontSelector(CSSFontSelector::create(*this))
    532533#if ENABLE(WEB_REPLAY)
    533534    , m_inputCursor(EmptyInputCursor::create())
     
    563564    initSecurityContext();
    564565    initDNSPrefetch();
     566
     567    m_fontSelector->registerForInvalidationCallbacks(*this);
    565568
    566569    for (auto& nodeListAndCollectionCount : m_nodeListAndCollectionCounts)
     
    638641
    639642    clearStyleResolver(); // We need to destroy CSSFontSelector before destroying m_cachedResourceLoader.
     643    m_fontSelector->clearDocument();
     644    m_fontSelector->unregisterForInvalidationCallbacks(*this);
    640645
    641646    // It's possible for multiple Documents to end up referencing the same CachedResourceLoader (e.g., SVGImages
     
    22092214}
    22102215
    2211 CSSFontSelector& Document::fontSelector()
    2212 {
    2213     if (!m_fontSelector) {
    2214         m_fontSelector = CSSFontSelector::create(*this);
    2215         m_fontSelector->registerForInvalidationCallbacks(*this);
    2216     }
    2217     return *m_fontSelector;
    2218 }
    2219 
    22202216void Document::clearStyleResolver()
    22212217{
     
    22232219    m_userAgentShadowTreeStyleResolver = nullptr;
    22242220
    2225     // FIXME: It would be better if the FontSelector could survive this operation.
    2226     if (m_fontSelector) {
    2227         m_fontSelector->clearDocument();
    2228         m_fontSelector->unregisterForInvalidationCallbacks(*this);
    2229         m_fontSelector = nullptr;
    2230     }
     2221    m_fontSelector->buildStarted();
    22312222}
    22322223
  • trunk/Source/WebCore/dom/Document.h

    r201739 r201799  
    505505    StyleResolver& userAgentShadowTreeStyleResolver();
    506506
    507     CSSFontSelector& fontSelector();
     507    CSSFontSelector& fontSelector() { return m_fontSelector; }
    508508
    509509    void notifyRemovePendingSheetIfNeeded();
     
    17371737#endif
    17381738
    1739     RefPtr<CSSFontSelector> m_fontSelector;
     1739    Ref<CSSFontSelector> m_fontSelector;
    17401740
    17411741#if ENABLE(WEB_REPLAY)
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r201673 r201799  
    493493
    494494    Element* documentElement = m_document.documentElement();
    495     if (!documentElement)
     495    if (!documentElement) {
     496        m_document.ensureStyleResolver();
    496497        return nullptr;
     498    }
    497499    if (change != Force && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
    498500        return nullptr;
Note: See TracChangeset for help on using the changeset viewer.