Changeset 207339 in webkit


Ignore:
Timestamp:
Oct 14, 2016 8:39:04 AM (8 years ago)
Author:
Antti Koivisto
Message:

Share inline stylesheets between shadow trees
https://bugs.webkit.org/show_bug.cgi?id=163353

Reviewed by Ryosuke Niwa and Andreas Kling.

If shadow trees have identical inline stylesheets the data structures can be shared.
In future this will also allow sharing style resolvers.

  • css/CSSStyleSheet.cpp:

(WebCore::CSSStyleSheet::createInline):

Move StyleSheetContents construction to the client.

  • css/parser/CSSParserMode.h:

(WebCore::CSSParserContextHash::hash):
(WebCore::CSSParserContextHash::equal):
(WTF::HashTraits<WebCore::CSSParserContext>::constructDeletedValue):
(WTF::HashTraits<WebCore::CSSParserContext>::isDeletedValue):
(WTF::HashTraits<WebCore::CSSParserContext>::emptyValue):

Make CSSParserContext hashable.

  • dom/ExtensionStyleSheets.cpp:

(WebCore::createExtensionsStyleSheet):
(WebCore::ExtensionStyleSheets::pageUserSheet):
(WebCore::ExtensionStyleSheets::updateInjectedStyleSheetCache):

Don't use CSSStyleSheet::createInline, these are not really inline stylesheets.
Code cleanups.

  • dom/InlineStyleSheetOwner.cpp:

(WebCore::parserContextForForElement):
(WebCore::makeInlineStyleSheetCacheKey):
(WebCore::inlineStyleSheetCache):

Implement a simple cache for sharing stylesheets with identical text and context.

(WebCore::InlineStyleSheetOwner::createSheet):
(WebCore::InlineStyleSheetOwner::clearCache):

  • dom/InlineStyleSheetOwner.h:
  • platform/MemoryPressureHandler.cpp:

(WebCore::MemoryPressureHandler::releaseNoncriticalMemory):

Location:
trunk/Source/WebCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r207338 r207339  
     12016-10-14  Antti Koivisto  <antti@apple.com>
     2
     3        Share inline stylesheets between shadow trees
     4        https://bugs.webkit.org/show_bug.cgi?id=163353
     5
     6        Reviewed by Ryosuke Niwa and Andreas Kling.
     7
     8        If shadow trees have identical inline stylesheets the data structures can be shared.
     9        In future this will also allow sharing style resolvers.
     10
     11        * css/CSSStyleSheet.cpp:
     12        (WebCore::CSSStyleSheet::createInline):
     13
     14            Move StyleSheetContents construction to the client.
     15
     16        * css/parser/CSSParserMode.h:
     17        (WebCore::CSSParserContextHash::hash):
     18        (WebCore::CSSParserContextHash::equal):
     19        (WTF::HashTraits<WebCore::CSSParserContext>::constructDeletedValue):
     20        (WTF::HashTraits<WebCore::CSSParserContext>::isDeletedValue):
     21        (WTF::HashTraits<WebCore::CSSParserContext>::emptyValue):
     22
     23            Make CSSParserContext hashable.
     24
     25        * dom/ExtensionStyleSheets.cpp:
     26        (WebCore::createExtensionsStyleSheet):
     27        (WebCore::ExtensionStyleSheets::pageUserSheet):
     28        (WebCore::ExtensionStyleSheets::updateInjectedStyleSheetCache):
     29
     30            Don't use CSSStyleSheet::createInline, these are not really inline stylesheets.
     31            Code cleanups.
     32
     33        * dom/InlineStyleSheetOwner.cpp:
     34        (WebCore::parserContextForForElement):
     35        (WebCore::makeInlineStyleSheetCacheKey):
     36        (WebCore::inlineStyleSheetCache):
     37
     38            Implement a simple cache for sharing stylesheets with identical text and context.
     39
     40        (WebCore::InlineStyleSheetOwner::createSheet):
     41        (WebCore::InlineStyleSheetOwner::clearCache):
     42        * dom/InlineStyleSheetOwner.h:
     43        * platform/MemoryPressureHandler.cpp:
     44        (WebCore::MemoryPressureHandler::releaseNoncriticalMemory):
     45
    1462016-10-14  Chris Dumez  <cdumez@apple.com>
    247
  • trunk/Source/WebCore/css/CSSStyleSheet.cpp

    r206951 r207339  
    9090}
    9191
    92 Ref<CSSStyleSheet> CSSStyleSheet::createInline(Node& ownerNode, const URL& baseURL, const TextPosition& startPosition, const String& encoding)
    93 {
    94     CSSParserContext parserContext(ownerNode.document(), baseURL, encoding);
    95     return adoptRef(*new CSSStyleSheet(StyleSheetContents::create(baseURL.string(), parserContext), ownerNode, startPosition, true, true));
     92Ref<CSSStyleSheet> CSSStyleSheet::createInline(Ref<StyleSheetContents>&& sheet, Element& owner, const TextPosition& startPosition)
     93{
     94    return adoptRef(*new CSSStyleSheet(WTFMove(sheet), owner, startPosition, true, true));
    9695}
    9796
  • trunk/Source/WebCore/css/CSSStyleSheet.h

    r206917 r207339  
    4040class CachedCSSStyleSheet;
    4141class Document;
     42class Element;
    4243class MediaQuerySet;
    4344class SecurityOrigin;
     
    5556    static Ref<CSSStyleSheet> create(Ref<StyleSheetContents>&&, CSSImportRule* ownerRule = 0);
    5657    static Ref<CSSStyleSheet> create(Ref<StyleSheetContents>&&, Node& ownerNode, const Optional<bool>& isOriginClean = Nullopt);
    57     static Ref<CSSStyleSheet> createInline(Node&, const URL&, const TextPosition& startPosition = TextPosition::minimumPosition(), const String& encoding = String());
     58    static Ref<CSSStyleSheet> createInline(Ref<StyleSheetContents>&&, Element& owner, const TextPosition& startPosition);
    5859
    5960    virtual ~CSSStyleSheet();
  • trunk/Source/WebCore/css/parser/CSSParserMode.h

    r207291 r207339  
    3333
    3434#include "URL.h"
     35#include "URLHash.h"
     36#include <wtf/HashFunctions.h>
     37#include <wtf/text/StringHash.h>
    3538
    3639namespace WebCore {
     
    115118WEBCORE_EXPORT const CSSParserContext& strictCSSParserContext();
    116119
     120struct CSSParserContextHash {
     121    static unsigned hash(const CSSParserContext& key)
     122    {
     123        auto hash = URLHash::hash(key.baseURL);
     124        hash ^= StringHash::hash(key.charset);
     125        unsigned bits = key.isHTMLDocument                  << 0
     126            & key.isHTMLDocument                            << 1
     127#if ENABLE(CSS_GRID_LAYOUT)
     128            & key.cssGridLayoutEnabled                      << 2
     129#endif
     130#if ENABLE(TEXT_AUTOSIZING)
     131            & key.textAutosizingEnabled                     << 3
     132#endif
     133            & key.needsSiteSpecificQuirks                   << 4
     134            & key.enforcesCSSMIMETypeInNoQuirksMode         << 5
     135            & key.useLegacyBackgroundSizeShorthandBehavior  << 6
     136            & key.springTimingFunctionEnabled               << 7
     137            & key.useNewParser                              << 8
     138#if ENABLE(VARIATION_FONTS)
     139            & key.variationFontsEnabled                     << 9
     140#endif
     141            & key.mode                                      << 10;
     142        hash ^= WTF::intHash(bits);
     143        return hash;
     144    }
     145    static bool equal(const CSSParserContext& a, const CSSParserContext& b)
     146    {
     147        return a == b;
     148    }
     149    static const bool safeToCompareToEmptyOrDeleted = false;
    117150};
    118151
     152}
     153
     154namespace WTF {
     155template<> struct HashTraits<WebCore::CSSParserContext> : GenericHashTraits<WebCore::CSSParserContext> {
     156    static void constructDeletedValue(WebCore::CSSParserContext& slot) { new (NotNull, &slot.baseURL) WebCore::URL(WTF::HashTableDeletedValue); }
     157    static bool isDeletedValue(const WebCore::CSSParserContext& value) { return value.baseURL.isHashTableDeletedValue(); }
     158    static WebCore::CSSParserContext emptyValue() { return WebCore::CSSParserContext(WebCore::HTMLStandardMode); }
     159};
     160
     161template<> struct DefaultHash<WebCore::CSSParserContext> {
     162    typedef WebCore::CSSParserContextHash Hash;
     163};
     164}
     165
    119166#endif // CSSParserMode_h
  • trunk/Source/WebCore/dom/ExtensionStyleSheets.cpp

    r206917 r207339  
    6060}
    6161
     62static Ref<CSSStyleSheet> createExtensionsStyleSheet(Document& document, URL url, const String& text, UserStyleLevel level)
     63{
     64    auto contents = StyleSheetContents::create(url, CSSParserContext(document, url));
     65    auto styleSheet = CSSStyleSheet::create(contents.get(), document, true);
     66
     67    contents->setIsUserStyleSheet(level == UserStyleUserLevel);
     68    contents->parseString(text);
     69
     70    return styleSheet;
     71}
     72
    6273CSSStyleSheet* ExtensionStyleSheets::pageUserSheet()
    6374{
     
    7384        return 0;
    7485   
    75     // Parse the sheet and cache it.
    76     m_pageUserSheet = CSSStyleSheet::createInline(m_document, m_document.settings()->userStyleSheetLocation());
    77     m_pageUserSheet->contents().setIsUserStyleSheet(true);
    78     m_pageUserSheet->contents().parseString(userSheetText);
     86    m_pageUserSheet = createExtensionsStyleSheet(m_document, m_document.settings()->userStyleSheetLocation(), userSheetText, UserStyleUserLevel);
     87
    7988    return m_pageUserSheet.get();
    8089}
     
    126135            return;
    127136
    128         RefPtr<CSSStyleSheet> sheet = CSSStyleSheet::createInline(const_cast<Document&>(m_document), userStyleSheet.url());
    129         bool isUserStyleSheet = userStyleSheet.level() == UserStyleUserLevel;
    130         if (isUserStyleSheet)
    131             m_injectedUserStyleSheets.append(sheet);
     137        auto sheet = createExtensionsStyleSheet(const_cast<Document&>(m_document), userStyleSheet.url(), userStyleSheet.source(), userStyleSheet.level());
     138
     139        if (userStyleSheet.level() == UserStyleUserLevel)
     140            m_injectedUserStyleSheets.append(WTFMove(sheet));
    132141        else
    133             m_injectedAuthorStyleSheets.append(sheet);
    134 
    135         sheet->contents().setIsUserStyleSheet(isUserStyleSheet);
    136         sheet->contents().parseString(userStyleSheet.source());
     142            m_injectedAuthorStyleSheets.append(WTFMove(sheet));
    137143    });
    138144   
     
    141147        static NeverDestroyed<URL> captionsStyleSheetURL(ParsedURLString, "user-captions-override:01F6AF12-C3B0-4F70-AF5E-A3E00234DC23");
    142148
    143         RefPtr<CSSStyleSheet> sheet = CSSStyleSheet::createInline(const_cast<Document&>(m_document), captionsStyleSheetURL.get());
    144         m_injectedAuthorStyleSheets.append(sheet);
    145 
    146         sheet->contents().setIsUserStyleSheet(false);
    147         sheet->contents().parseString(owningPage->captionUserPreferencesStyleSheet());
     149        auto sheet = createExtensionsStyleSheet(const_cast<Document&>(m_document), captionsStyleSheetURL, owningPage->captionUserPreferencesStyleSheet(), UserStyleAuthorLevel);
     150
     151        m_injectedAuthorStyleSheets.append(WTFMove(sheet));
    148152    }
    149153}
  • trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp

    r207291 r207339  
    3131#include "StyleSheetContents.h"
    3232#include "TextNodeTraversal.h"
     33#include <wtf/HashMap.h>
    3334#include <wtf/NeverDestroyed.h>
    3435
    3536namespace WebCore {
     37
     38using InlineStyleSheetCacheKey = std::pair<String, CSSParserContext>;
     39using InlineStyleSheetCache = HashMap<InlineStyleSheetCacheKey, RefPtr<StyleSheetContents>>;
     40
     41static InlineStyleSheetCache& inlineStyleSheetCache()
     42{
     43    static NeverDestroyed<InlineStyleSheetCache> cache;
     44    return cache;
     45}
     46
     47static CSSParserContext parserContextForForElement(const Element& element)
     48{
     49    auto* shadowRoot = element.containingShadowRoot();
     50    // User agent shadow trees can't contain document-relative URLs. Use blank URL as base allowing cross-document sharing.
     51    auto& baseURL = shadowRoot && shadowRoot->mode() == ShadowRoot::Mode::UserAgent ? blankURL() : element.document().baseURL();
     52
     53    return CSSParserContext { element.document(), baseURL, element.document().encoding() };
     54}
     55
     56static Optional<InlineStyleSheetCacheKey> makeInlineStyleSheetCacheKey(const String& text, const Element& element)
     57{
     58    // Only cache for shadow trees. Main document inline stylesheets are generally unique and can't be shared between documents.
     59    // FIXME: This could be relaxed when a stylesheet does not contain document-relative URLs (or #urls).
     60    if (!element.isInShadowTree())
     61        return { };
     62
     63    return std::make_pair(text, parserContextForForElement(element));
     64}
    3665
    3766InlineStyleSheetOwner::InlineStyleSheetOwner(Document& document, bool createdByParser)
     
    153182        m_styleScope->addPendingSheet();
    154183
     184    auto cacheKey = makeInlineStyleSheetCacheKey(text, element);
     185    if (cacheKey) {
     186        if (auto* cachedSheet = inlineStyleSheetCache().get(*cacheKey)) {
     187            ASSERT(cachedSheet->isCacheable());
     188            m_sheet = CSSStyleSheet::createInline(*cachedSheet, element, m_startTextPosition);
     189            m_sheet->setMediaQueries(mediaQueries.releaseNonNull());
     190            m_sheet->setTitle(element.title());
     191
     192            sheetLoaded(element);
     193            element.notifyLoadedSheetAndAllCriticalSubresources(false);
     194            return;
     195        }
     196    }
     197
    155198    m_loading = true;
    156199
    157     m_sheet = CSSStyleSheet::createInline(element, URL(), m_startTextPosition, document.encoding());
     200    auto contents = StyleSheetContents::create(String(), parserContextForForElement(element));
     201
     202    m_sheet = CSSStyleSheet::createInline(contents.get(), element, m_startTextPosition);
    158203    m_sheet->setMediaQueries(mediaQueries.releaseNonNull());
    159204    m_sheet->setTitle(element.title());
    160     m_sheet->contents().parseStringAtPosition(text, m_startTextPosition, m_isParsingChildren);
     205
     206    contents->parseStringAtPosition(text, m_startTextPosition, m_isParsingChildren);
    161207
    162208    m_loading = false;
    163209
    164     if (m_sheet)
    165         m_sheet->contents().checkLoaded();
     210    contents->checkLoaded();
     211
     212    if (cacheKey && contents->isCacheable()) {
     213        inlineStyleSheetCache().add(*cacheKey, &m_sheet->contents());
     214
     215        // Prevent pathological growth.
     216        const size_t maximumInlineStyleSheetCacheSize = 50;
     217        if (inlineStyleSheetCache().size() > maximumInlineStyleSheetCacheSize)
     218            inlineStyleSheetCache().remove(inlineStyleSheetCache().begin());
     219    }
    166220}
    167221
     
    190244}
    191245
    192 }
     246void InlineStyleSheetOwner::clearCache()
     247{
     248    inlineStyleSheetCache().clear();
     249}
     250
     251}
  • trunk/Source/WebCore/dom/InlineStyleSheetOwner.h

    r207291 r207339  
    5353    Style::Scope* styleScope() { return m_styleScope; }
    5454
     55    static void clearCache();
     56
    5557private:
    5658    void createSheet(Element&, const String& text);
  • trunk/Source/WebCore/platform/MemoryPressureHandler.cpp

    r207291 r207339  
    3434#include "GCController.h"
    3535#include "HTMLMediaElement.h"
     36#include "InlineStyleSheetOwner.h"
    3637#include "InspectorInstrumentation.h"
    3738#include "Logging.h"
     
    104105        StyledElement::clearPresentationAttributeCache();
    105106    }
     107
     108    {
     109        ReliefLogger log("Clear inline stylesheet cache");
     110        InlineStyleSheetOwner::clearCache();
     111    }
    106112}
    107113
Note: See TracChangeset for help on using the changeset viewer.