Changeset 207286 in webkit


Ignore:
Timestamp:
Oct 13, 2016 4:59:19 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/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/InlineStyleSheetOwner.cpp:

(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:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r207285 r207286  
     12016-10-13  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/parser/CSSParserMode.h:
     12        (WebCore::CSSParserContextHash::hash):
     13        (WebCore::CSSParserContextHash::equal):
     14        (WTF::HashTraits<WebCore::CSSParserContext>::constructDeletedValue):
     15        (WTF::HashTraits<WebCore::CSSParserContext>::isDeletedValue):
     16        (WTF::HashTraits<WebCore::CSSParserContext>::emptyValue):
     17
     18            Make CSSParserContext hashable.
     19
     20        * dom/InlineStyleSheetOwner.cpp:
     21        (WebCore::makeInlineStyleSheetCacheKey):
     22        (WebCore::inlineStyleSheetCache):
     23
     24            Implement a simple cache for sharing stylesheets with identical text and context.
     25
     26        (WebCore::InlineStyleSheetOwner::createSheet):
     27        (WebCore::InlineStyleSheetOwner::clearCache):
     28        * dom/InlineStyleSheetOwner.h:
     29        * platform/MemoryPressureHandler.cpp:
     30        (WebCore::MemoryPressureHandler::releaseNoncriticalMemory):
     31
    1322016-10-13  Antti Koivisto  <antti@apple.com>
    233
  • trunk/Source/WebCore/css/parser/CSSParserMode.h

    r207285 r207286  
    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/InlineStyleSheetOwner.cpp

    r207285 r207286  
    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 URL inlineStyleSheetBaseURLForElement(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    return shadowRoot && shadowRoot->mode() == ShadowRoot::Mode::UserAgent ? blankURL() : element.document().baseURL();
     52}
     53
     54static Optional<InlineStyleSheetCacheKey> makeInlineStyleSheetCacheKey(const String& text, const Element& element)
     55{
     56    if (text.isEmpty())
     57        return { };
     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    CSSParserContext context { element.document(), inlineStyleSheetBaseURLForElement(element) };
     64    return std::make_pair(text, context);
     65}
    3666
    3767InlineStyleSheetOwner::InlineStyleSheetOwner(Document& document, bool createdByParser)
     
    153183        m_styleScope->addPendingSheet();
    154184
     185    auto cacheKey = makeInlineStyleSheetCacheKey(text, element);
     186    if (cacheKey) {
     187        if (auto* cachedSheet = inlineStyleSheetCache().get(*cacheKey)) {
     188            ASSERT(cachedSheet->isCacheable());
     189            m_sheet = CSSStyleSheet::create(*cachedSheet, element);
     190            sheetLoaded(element);
     191            element.notifyLoadedSheetAndAllCriticalSubresources(false);
     192            return;
     193        }
     194    }
     195
    155196    m_loading = true;
    156197
    157     m_sheet = CSSStyleSheet::createInline(element, URL(), m_startTextPosition, document.encoding());
     198    m_sheet = CSSStyleSheet::createInline(element, inlineStyleSheetBaseURLForElement(element), m_startTextPosition, document.encoding());
    158199    m_sheet->setMediaQueries(mediaQueries.releaseNonNull());
    159200    m_sheet->setTitle(element.title());
     
    164205    if (m_sheet)
    165206        m_sheet->contents().checkLoaded();
     207
     208    if (cacheKey && m_sheet && m_sheet->contents().isCacheable()) {
     209        inlineStyleSheetCache().add(*cacheKey, &m_sheet->contents());
     210
     211        // Prevent pathological growth.
     212        const size_t maximumInlineStyleSheetCacheSize = 50;
     213        if (inlineStyleSheetCache().size() > maximumInlineStyleSheetCacheSize)
     214            inlineStyleSheetCache().remove(inlineStyleSheetCache().begin());
     215    }
    166216}
    167217
     
    190240}
    191241
    192 }
     242void InlineStyleSheetOwner::clearCache()
     243{
     244    inlineStyleSheetCache().clear();
     245}
     246
     247}
  • trunk/Source/WebCore/dom/InlineStyleSheetOwner.h

    r207285 r207286  
    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

    r207285 r207286  
    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.