Diff
Modified: trunk/Source/WebCore/ChangeLog (207338 => 207339)
--- trunk/Source/WebCore/ChangeLog 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/ChangeLog 2016-10-14 15:39:04 UTC (rev 207339)
@@ -1,3 +1,48 @@
+2016-10-14 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/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):
+
2016-10-14 Chris Dumez <cdu...@apple.com>
[Mac] Allow throttling of background tabs that have media elements with no audible audio
Modified: trunk/Source/WebCore/css/CSSStyleSheet.cpp (207338 => 207339)
--- trunk/Source/WebCore/css/CSSStyleSheet.cpp 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/css/CSSStyleSheet.cpp 2016-10-14 15:39:04 UTC (rev 207339)
@@ -89,10 +89,9 @@
return adoptRef(*new CSSStyleSheet(WTFMove(sheet), ownerNode, TextPosition::minimumPosition(), false, isCleanOrigin));
}
-Ref<CSSStyleSheet> CSSStyleSheet::createInline(Node& ownerNode, const URL& baseURL, const TextPosition& startPosition, const String& encoding)
+Ref<CSSStyleSheet> CSSStyleSheet::createInline(Ref<StyleSheetContents>&& sheet, Element& owner, const TextPosition& startPosition)
{
- CSSParserContext parserContext(ownerNode.document(), baseURL, encoding);
- return adoptRef(*new CSSStyleSheet(StyleSheetContents::create(baseURL.string(), parserContext), ownerNode, startPosition, true, true));
+ return adoptRef(*new CSSStyleSheet(WTFMove(sheet), owner, startPosition, true, true));
}
CSSStyleSheet::CSSStyleSheet(Ref<StyleSheetContents>&& contents, CSSImportRule* ownerRule)
Modified: trunk/Source/WebCore/css/CSSStyleSheet.h (207338 => 207339)
--- trunk/Source/WebCore/css/CSSStyleSheet.h 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/css/CSSStyleSheet.h 2016-10-14 15:39:04 UTC (rev 207339)
@@ -39,6 +39,7 @@
class CSSStyleSheet;
class CachedCSSStyleSheet;
class Document;
+class Element;
class MediaQuerySet;
class SecurityOrigin;
class StyleRuleKeyframes;
@@ -54,7 +55,7 @@
public:
static Ref<CSSStyleSheet> create(Ref<StyleSheetContents>&&, CSSImportRule* ownerRule = 0);
static Ref<CSSStyleSheet> create(Ref<StyleSheetContents>&&, Node& ownerNode, const Optional<bool>& isOriginClean = Nullopt);
- static Ref<CSSStyleSheet> createInline(Node&, const URL&, const TextPosition& startPosition = TextPosition::minimumPosition(), const String& encoding = String());
+ static Ref<CSSStyleSheet> createInline(Ref<StyleSheetContents>&&, Element& owner, const TextPosition& startPosition);
virtual ~CSSStyleSheet();
Modified: trunk/Source/WebCore/css/parser/CSSParserMode.h (207338 => 207339)
--- trunk/Source/WebCore/css/parser/CSSParserMode.h 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/css/parser/CSSParserMode.h 2016-10-14 15:39:04 UTC (rev 207339)
@@ -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/ExtensionStyleSheets.cpp (207338 => 207339)
--- trunk/Source/WebCore/dom/ExtensionStyleSheets.cpp 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/dom/ExtensionStyleSheets.cpp 2016-10-14 15:39:04 UTC (rev 207339)
@@ -59,6 +59,17 @@
{
}
+static Ref<CSSStyleSheet> createExtensionsStyleSheet(Document& document, URL url, const String& text, UserStyleLevel level)
+{
+ auto contents = StyleSheetContents::create(url, CSSParserContext(document, url));
+ auto styleSheet = CSSStyleSheet::create(contents.get(), document, true);
+
+ contents->setIsUserStyleSheet(level == UserStyleUserLevel);
+ contents->parseString(text);
+
+ return styleSheet;
+}
+
CSSStyleSheet* ExtensionStyleSheets::pageUserSheet()
{
if (m_pageUserSheet)
@@ -72,10 +83,8 @@
if (userSheetText.isEmpty())
return 0;
- // Parse the sheet and cache it.
- m_pageUserSheet = CSSStyleSheet::createInline(m_document, m_document.settings()->userStyleSheetLocation());
- m_pageUserSheet->contents().setIsUserStyleSheet(true);
- m_pageUserSheet->contents().parseString(userSheetText);
+ m_pageUserSheet = createExtensionsStyleSheet(m_document, m_document.settings()->userStyleSheetLocation(), userSheetText, UserStyleUserLevel);
+
return m_pageUserSheet.get();
}
@@ -125,15 +134,12 @@
if (!UserContentURLPattern::matchesPatterns(m_document.url(), userStyleSheet.whitelist(), userStyleSheet.blacklist()))
return;
- RefPtr<CSSStyleSheet> sheet = CSSStyleSheet::createInline(const_cast<Document&>(m_document), userStyleSheet.url());
- bool isUserStyleSheet = userStyleSheet.level() == UserStyleUserLevel;
- if (isUserStyleSheet)
- m_injectedUserStyleSheets.append(sheet);
+ auto sheet = createExtensionsStyleSheet(const_cast<Document&>(m_document), userStyleSheet.url(), userStyleSheet.source(), userStyleSheet.level());
+
+ if (userStyleSheet.level() == UserStyleUserLevel)
+ m_injectedUserStyleSheets.append(WTFMove(sheet));
else
- m_injectedAuthorStyleSheets.append(sheet);
-
- sheet->contents().setIsUserStyleSheet(isUserStyleSheet);
- sheet->contents().parseString(userStyleSheet.source());
+ m_injectedAuthorStyleSheets.append(WTFMove(sheet));
});
if (!owningPage->captionUserPreferencesStyleSheet().isEmpty()) {
@@ -140,11 +146,9 @@
// Identify our override style sheet with a unique URL - a new scheme and a UUID.
static NeverDestroyed<URL> captionsStyleSheetURL(ParsedURLString, "user-captions-override:01F6AF12-C3B0-4F70-AF5E-A3E00234DC23");
- RefPtr<CSSStyleSheet> sheet = CSSStyleSheet::createInline(const_cast<Document&>(m_document), captionsStyleSheetURL.get());
- m_injectedAuthorStyleSheets.append(sheet);
+ auto sheet = createExtensionsStyleSheet(const_cast<Document&>(m_document), captionsStyleSheetURL, owningPage->captionUserPreferencesStyleSheet(), UserStyleAuthorLevel);
- sheet->contents().setIsUserStyleSheet(false);
- sheet->contents().parseString(owningPage->captionUserPreferencesStyleSheet());
+ m_injectedAuthorStyleSheets.append(WTFMove(sheet));
}
}
Modified: trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp (207338 => 207339)
--- trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/dom/InlineStyleSheetOwner.cpp 2016-10-14 15:39:04 UTC (rev 207339)
@@ -30,10 +30,39 @@
#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 CSSParserContext parserContextForForElement(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.
+ auto& baseURL = shadowRoot && shadowRoot->mode() == ShadowRoot::Mode::UserAgent ? blankURL() : element.document().baseURL();
+
+ return CSSParserContext { element.document(), baseURL, element.document().encoding() };
+}
+
+static Optional<InlineStyleSheetCacheKey> makeInlineStyleSheetCacheKey(const String& text, const Element& element)
+{
+ // 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 { };
+
+ return std::make_pair(text, parserContextForForElement(element));
+}
+
InlineStyleSheetOwner::InlineStyleSheetOwner(Document& document, bool createdByParser)
: m_isParsingChildren(createdByParser)
, m_loading(false)
@@ -152,17 +181,42 @@
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::createInline(*cachedSheet, element, m_startTextPosition);
+ m_sheet->setMediaQueries(mediaQueries.releaseNonNull());
+ m_sheet->setTitle(element.title());
+
+ sheetLoaded(element);
+ element.notifyLoadedSheetAndAllCriticalSubresources(false);
+ return;
+ }
+ }
+
m_loading = true;
- m_sheet = CSSStyleSheet::createInline(element, URL(), m_startTextPosition, document.encoding());
+ auto contents = StyleSheetContents::create(String(), parserContextForForElement(element));
+
+ m_sheet = CSSStyleSheet::createInline(contents.get(), element, m_startTextPosition);
m_sheet->setMediaQueries(mediaQueries.releaseNonNull());
m_sheet->setTitle(element.title());
- m_sheet->contents().parseStringAtPosition(text, m_startTextPosition, m_isParsingChildren);
+ contents->parseStringAtPosition(text, m_startTextPosition, m_isParsingChildren);
+
m_loading = false;
- if (m_sheet)
- m_sheet->contents().checkLoaded();
+ contents->checkLoaded();
+
+ if (cacheKey && 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 +243,9 @@
m_styleScope->addPendingSheet();
}
+void InlineStyleSheetOwner::clearCache()
+{
+ inlineStyleSheetCache().clear();
}
+
+}
Modified: trunk/Source/WebCore/dom/InlineStyleSheetOwner.h (207338 => 207339)
--- trunk/Source/WebCore/dom/InlineStyleSheetOwner.h 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/dom/InlineStyleSheetOwner.h 2016-10-14 15:39:04 UTC (rev 207339)
@@ -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 (207338 => 207339)
--- trunk/Source/WebCore/platform/MemoryPressureHandler.cpp 2016-10-14 14:56:05 UTC (rev 207338)
+++ trunk/Source/WebCore/platform/MemoryPressureHandler.cpp 2016-10-14 15:39:04 UTC (rev 207339)
@@ -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)