ExtensionStyleSheets.cpp [plain text]
#include "config.h"
#include "ExtensionStyleSheets.h"
#include "CSSStyleSheet.h"
#include "Element.h"
#include "HTMLIFrameElement.h"
#include "HTMLLinkElement.h"
#include "HTMLStyleElement.h"
#include "Page.h"
#include "PageGroup.h"
#include "ProcessingInstruction.h"
#include "SVGNames.h"
#include "SVGStyleElement.h"
#include "Settings.h"
#include "StyleInvalidationAnalysis.h"
#include "StyleResolver.h"
#include "StyleSheetContents.h"
#include "StyleSheetList.h"
#include "UserContentController.h"
#include "UserContentURLPattern.h"
#include "UserStyleSheet.h"
namespace WebCore {
using namespace ContentExtensions;
using namespace HTMLNames;
ExtensionStyleSheets::ExtensionStyleSheets(Document& document)
: m_document(document)
, m_styleResolverChangedTimer(*this, &ExtensionStyleSheets::styleResolverChangedTimerFired)
{
}
CSSStyleSheet* ExtensionStyleSheets::pageUserSheet()
{
if (m_pageUserSheet)
return m_pageUserSheet.get();
Page* owningPage = m_document.page();
if (!owningPage)
return 0;
String userSheetText = owningPage->userStyleSheet();
if (userSheetText.isEmpty())
return 0;
m_pageUserSheet = CSSStyleSheet::createInline(m_document, m_document.settings()->userStyleSheetLocation());
m_pageUserSheet->contents().setIsUserStyleSheet(true);
m_pageUserSheet->contents().parseString(userSheetText);
return m_pageUserSheet.get();
}
void ExtensionStyleSheets::clearPageUserSheet()
{
if (m_pageUserSheet) {
m_pageUserSheet = nullptr;
m_document.styleResolverChanged(DeferRecalcStyle);
}
}
void ExtensionStyleSheets::updatePageUserSheet()
{
clearPageUserSheet();
if (pageUserSheet())
m_document.styleResolverChanged(RecalcStyleImmediately);
}
const Vector<RefPtr<CSSStyleSheet>>& ExtensionStyleSheets::injectedUserStyleSheets() const
{
updateInjectedStyleSheetCache();
return m_injectedUserStyleSheets;
}
const Vector<RefPtr<CSSStyleSheet>>& ExtensionStyleSheets::injectedAuthorStyleSheets() const
{
updateInjectedStyleSheetCache();
return m_injectedAuthorStyleSheets;
}
void ExtensionStyleSheets::updateInjectedStyleSheetCache() const
{
if (m_injectedStyleSheetCacheValid)
return;
m_injectedStyleSheetCacheValid = true;
m_injectedUserStyleSheets.clear();
m_injectedAuthorStyleSheets.clear();
Page* owningPage = m_document.page();
if (!owningPage)
return;
owningPage->userContentProvider().forEachUserStyleSheet([&](const UserStyleSheet& userStyleSheet) {
if (userStyleSheet.injectedFrames() == InjectInTopFrameOnly && m_document.ownerElement())
return;
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);
else
m_injectedAuthorStyleSheets.append(sheet);
sheet->contents().setIsUserStyleSheet(isUserStyleSheet);
sheet->contents().parseString(userStyleSheet.source());
});
if (!owningPage->captionUserPreferencesStyleSheet().isEmpty()) {
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);
sheet->contents().setIsUserStyleSheet(false);
sheet->contents().parseString(owningPage->captionUserPreferencesStyleSheet());
}
}
void ExtensionStyleSheets::invalidateInjectedStyleSheetCache()
{
if (!m_injectedStyleSheetCacheValid)
return;
m_injectedStyleSheetCacheValid = false;
if (m_injectedUserStyleSheets.isEmpty() && m_injectedAuthorStyleSheets.isEmpty())
return;
m_document.styleResolverChanged(DeferRecalcStyle);
}
void ExtensionStyleSheets::addUserStyleSheet(Ref<StyleSheetContents>&& userSheet)
{
ASSERT(userSheet.get().isUserStyleSheet());
m_userStyleSheets.append(CSSStyleSheet::create(WTFMove(userSheet), &m_document));
m_document.styleResolverChanged(RecalcStyleImmediately);
}
void ExtensionStyleSheets::addAuthorStyleSheetForTesting(Ref<StyleSheetContents>&& authorSheet)
{
ASSERT(!authorSheet.get().isUserStyleSheet());
m_authorStyleSheetsForTesting.append(CSSStyleSheet::create(WTFMove(authorSheet), &m_document));
m_document.styleResolverChanged(RecalcStyleImmediately);
}
#if ENABLE(CONTENT_EXTENSIONS)
void ExtensionStyleSheets::addDisplayNoneSelector(const String& identifier, const String& selector, uint32_t selectorID)
{
auto result = m_contentExtensionSelectorSheets.add(identifier, nullptr);
if (result.isNewEntry) {
result.iterator->value = ContentExtensionStyleSheet::create(m_document);
m_userStyleSheets.append(&result.iterator->value->styleSheet());
}
if (result.iterator->value->addDisplayNoneSelector(selector, selectorID))
m_styleResolverChangedTimer.startOneShot(0);
}
void ExtensionStyleSheets::maybeAddContentExtensionSheet(const String& identifier, StyleSheetContents& sheet)
{
ASSERT(sheet.isUserStyleSheet());
if (m_contentExtensionSheets.contains(identifier))
return;
Ref<CSSStyleSheet> cssSheet = CSSStyleSheet::create(sheet, &m_document);
m_contentExtensionSheets.set(identifier, &cssSheet.get());
m_userStyleSheets.append(adoptRef(cssSheet.leakRef()));
m_styleResolverChangedTimer.startOneShot(0);
}
#endif // ENABLE(CONTENT_EXTENSIONS)
void ExtensionStyleSheets::styleResolverChangedTimerFired()
{
m_document.styleResolverChanged(RecalcStyleImmediately);
}
void ExtensionStyleSheets::detachFromDocument()
{
if (m_pageUserSheet)
m_pageUserSheet->detachFromDocument();
for (auto& sheet : m_injectedUserStyleSheets)
sheet->detachFromDocument();
for (auto& sheet : m_injectedAuthorStyleSheets)
sheet->detachFromDocument();
for (auto& sheet : m_userStyleSheets)
sheet->detachFromDocument();
for (auto& sheet : m_authorStyleSheetsForTesting)
sheet->detachFromDocument();
}
}