Diff
Modified: trunk/Source/WebCore/ChangeLog (207283 => 207284)
--- trunk/Source/WebCore/ChangeLog 2016-10-13 11:41:22 UTC (rev 207283)
+++ trunk/Source/WebCore/ChangeLog 2016-10-13 11:47:41 UTC (rev 207284)
@@ -76,6 +76,37 @@
2016-10-13 Antti Koivisto <an...@apple.com>
+ 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):
+
+2016-10-13 Antti Koivisto <an...@apple.com>
+
Support scoped style for user agent shadow trees
https://bugs.webkit.org/show_bug.cgi?id=163212
<rdar://problem/28715318>
Modified: trunk/Source/WebCore/css/parser/CSSParserMode.h (207283 => 207284)
--- trunk/Source/WebCore/css/parser/CSSParserMode.h 2016-10-13 11:41:22 UTC (rev 207283)
+++ trunk/Source/WebCore/css/parser/CSSParserMode.h 2016-10-13 11:47:41 UTC (rev 207284)
@@ -32,6 +32,9 @@
#define CSSParserMode_h
#include "URL.h"
+#include "URLHash.h"
+#include <wtf/HashFunctions.h>
+#include <wtf/text/StringHash.h>
namespace WebCore {
@@ -114,6 +117,50 @@
WEBCORE_EXPORT const CSSParserContext& strictCSSParserContext();
+struct CSSParserContextHash {
+ static unsigned hash(const CSSParserContext& key)
+ {
+ auto hash = URLHash::hash(key.baseURL);
+ hash ^= StringHash::hash(key.charset);
+ unsigned bits = key.isHTMLDocument << 0
+ & key.isHTMLDocument << 1
+#if ENABLE(CSS_GRID_LAYOUT)
+ & key.cssGridLayoutEnabled << 2
+#endif
+#if ENABLE(TEXT_AUTOSIZING)
+ & key.textAutosizingEnabled << 3
+#endif
+ & key.needsSiteSpecificQuirks << 4
+ & key.enforcesCSSMIMETypeInNoQuirksMode << 5
+ & key.useLegacyBackgroundSizeShorthandBehavior << 6
+ & key.springTimingFunctionEnabled << 7
+ & key.useNewParser << 8
+#if ENABLE(VARIATION_FONTS)
+ & key.variationFontsEnabled << 9
+#endif
+ & key.mode << 10;
+ hash ^= WTF::intHash(bits);
+ return hash;
+ }
+ static bool equal(const CSSParserContext& a, const CSSParserContext& b)
+ {
+ return a == b;
+ }
+ static const bool safeToCompareToEmptyOrDeleted = false;
};
+}
+
+namespace WTF {
+template<> struct HashTraits<WebCore::CSSParserContext> : GenericHashTraits<WebCore::CSSParserContext> {
+ static void constructDeletedValue(WebCore::CSSParserContext& slot) { new (NotNull, &slot.baseURL) WebCore::URL(WTF::HashTableDeletedValue); }
+ static bool isDeletedValue(const WebCore::CSSParserContext& value) { return value.baseURL.isHashTableDeletedValue(); }
+ static WebCore::CSSParserContext emptyValue() { return WebCore::CSSParserContext(WebCore::HTMLStandardMode); }
+};
+
+template<> struct DefaultHash<WebCore::CSSParserContext> {
+ typedef WebCore::CSSParserContextHash Hash;
+};
+}
+
#endif // CSSParserMode_h
Modified: trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp (207283 => 207284)
--- trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp 2016-10-13 11:41:22 UTC (rev 207283)
+++ trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp 2016-10-13 11:47:41 UTC (rev 207284)
@@ -30,10 +30,40 @@
#include "StyleScope.h"
#include "StyleSheetContents.h"
#include "TextNodeTraversal.h"
+#include <wtf/HashMap.h>
#include <wtf/NeverDestroyed.h>
namespace WebCore {
+using InlineStyleSheetCacheKey = std::pair<String, CSSParserContext>;
+using InlineStyleSheetCache = HashMap<InlineStyleSheetCacheKey, RefPtr<StyleSheetContents>>;
+
+static InlineStyleSheetCache& inlineStyleSheetCache()
+{
+ static NeverDestroyed<InlineStyleSheetCache> cache;
+ return cache;
+}
+
+static URL inlineStyleSheetBaseURLForElement(const Element& element)
+{
+ auto* shadowRoot = element.containingShadowRoot();
+ // User agent shadow trees can't contain document-relative URLs. Use blank URL as base allowing cross-document sharing.
+ return shadowRoot && shadowRoot->mode() == ShadowRoot::Mode::UserAgent ? blankURL() : element.document().baseURL();
+}
+
+static Optional<InlineStyleSheetCacheKey> makeInlineStyleSheetCacheKey(const String& text, const Element& element)
+{
+ if (text.isEmpty())
+ return { };
+ // Only cache for shadow trees. Main document inline stylesheets are generally unique and can't be shared between documents.
+ // FIXME: This could be relaxed when a stylesheet does not contain document-relative URLs (or #urls).
+ if (!element.isInShadowTree())
+ return { };
+
+ CSSParserContext context { element.document(), inlineStyleSheetBaseURLForElement(element) };
+ return std::make_pair(text, context);
+}
+
InlineStyleSheetOwner::InlineStyleSheetOwner(Document& document, bool createdByParser)
: m_isParsingChildren(createdByParser)
, m_loading(false)
@@ -152,9 +182,20 @@
if (m_styleScope)
m_styleScope->addPendingSheet();
+ auto cacheKey = makeInlineStyleSheetCacheKey(text, element);
+ if (cacheKey) {
+ if (auto* cachedSheet = inlineStyleSheetCache().get(*cacheKey)) {
+ ASSERT(cachedSheet->isCacheable());
+ m_sheet = CSSStyleSheet::create(*cachedSheet, element);
+ sheetLoaded(element);
+ element.notifyLoadedSheetAndAllCriticalSubresources(false);
+ return;
+ }
+ }
+
m_loading = true;
- m_sheet = CSSStyleSheet::createInline(element, URL(), m_startTextPosition, document.encoding());
+ m_sheet = CSSStyleSheet::createInline(element, inlineStyleSheetBaseURLForElement(element), m_startTextPosition, document.encoding());
m_sheet->setMediaQueries(mediaQueries.releaseNonNull());
m_sheet->setTitle(element.title());
m_sheet->contents().parseStringAtPosition(text, m_startTextPosition, m_isParsingChildren);
@@ -163,6 +204,15 @@
if (m_sheet)
m_sheet->contents().checkLoaded();
+
+ if (cacheKey && m_sheet && m_sheet->contents().isCacheable()) {
+ inlineStyleSheetCache().add(*cacheKey, &m_sheet->contents());
+
+ // Prevent pathological growth.
+ const size_t maximumInlineStyleSheetCacheSize = 50;
+ if (inlineStyleSheetCache().size() > maximumInlineStyleSheetCacheSize)
+ inlineStyleSheetCache().remove(inlineStyleSheetCache().begin());
+ }
}
bool InlineStyleSheetOwner::isLoading() const
@@ -189,4 +239,9 @@
m_styleScope->addPendingSheet();
}
+void InlineStyleSheetOwner::clearCache()
+{
+ inlineStyleSheetCache().clear();
}
+
+}
Modified: trunk/Source/WebCore/dom/InlineStyleSheetOwner.h (207283 => 207284)
--- trunk/Source/WebCore/dom/InlineStyleSheetOwner.h 2016-10-13 11:41:22 UTC (rev 207283)
+++ trunk/Source/WebCore/dom/InlineStyleSheetOwner.h 2016-10-13 11:47:41 UTC (rev 207284)
@@ -52,6 +52,8 @@
Style::Scope* styleScope() { return m_styleScope; }
+ static void clearCache();
+
private:
void createSheet(Element&, const String& text);
void createSheetFromTextContents(Element&);
Modified: trunk/Source/WebCore/platform/MemoryPressureHandler.cpp (207283 => 207284)
--- trunk/Source/WebCore/platform/MemoryPressureHandler.cpp 2016-10-13 11:41:22 UTC (rev 207283)
+++ trunk/Source/WebCore/platform/MemoryPressureHandler.cpp 2016-10-13 11:47:41 UTC (rev 207284)
@@ -33,6 +33,7 @@
#include "FontCache.h"
#include "GCController.h"
#include "HTMLMediaElement.h"
+#include "InlineStyleSheetOwner.h"
#include "InspectorInstrumentation.h"
#include "Logging.h"
#include "MemoryCache.h"
@@ -103,6 +104,11 @@
ReliefLogger log("Prune presentation attribute cache");
StyledElement::clearPresentationAttributeCache();
}
+
+ {
+ ReliefLogger log("Clear inline stylesheet cache");
+ InlineStyleSheetOwner::clearCache();
+ }
}
void MemoryPressureHandler::releaseCriticalMemory(Synchronous synchronous)