namespace WebCore {
-DEFINE_GC_INFO(StyleSheetContents);
-
// Rough size estimate for the memory cache.
unsigned StyleSheetContents::estimatedSizeInBytes() const
{
, m_isInMemoryCache(false)
, m_hasFontFaceRule(false)
, m_hasMediaQueries(false)
+ , m_hasSingleOwnerDocument(true)
, m_parserContext(context)
{
}
StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
- : m_ownerRule(0)
+ : m_ownerRule(nullptr)
, m_originalURL(o.m_originalURL)
, m_encodingFromCharsetRule(o.m_encodingFromCharsetRule)
, m_importRules(o.m_importRules.size())
, m_isInMemoryCache(false)
, m_hasFontFaceRule(o.m_hasFontFaceRule)
, m_hasMediaQueries(o.m_hasMediaQueries)
+ , m_hasSingleOwnerDocument(true)
, m_parserContext(o.m_parserContext)
{
ASSERT(o.isCacheable());
StyleSheetContents::~StyleSheetContents()
{
- StyleEngine::removeSheet(this);
+#if !ENABLE(OILPAN)
clearRules();
+#endif
}
void StyleSheetContents::setHasSyntacticallyValidCSSHeader(bool isValidCss)
{
- if (maybeCacheable() && !isValidCss)
- StyleEngine::removeSheet(this);
+ if (!isValidCss) {
+ if (Document* document = clientSingleOwnerDocument())
+ removeSheetFromCache(document);
+ }
m_hasSyntacticallyValidCSSHeader = isValidCss;
}
-bool StyleSheetContents::maybeCacheable() const
+bool StyleSheetContents::isCacheable() const
{
+ // This would require dealing with multiple clients for load callbacks.
+ if (!loadCompleted())
+ return false;
// FIXME: StyleSheets with media queries can't be cached because their RuleSet
// is processed differently based off the media queries, which might resolve
// differently depending on the context of the parent CSSStyleSheet (e.g.
return true;
}
-bool StyleSheetContents::isCacheable() const
-{
- // This would require dealing with multiple clients for load callbacks.
- if (!loadCompleted())
- return false;
- return maybeCacheable();
-}
-
-void StyleSheetContents::parserAppendRule(PassRefPtr<StyleRuleBase> rule)
+void StyleSheetContents::parserAppendRule(PassRefPtrWillBeRawPtr<StyleRuleBase> rule)
{
ASSERT(!rule->isCharsetRule());
if (rule->isImportRule()) {
m_encodingFromCharsetRule = encoding;
}
-bool StyleSheetContents::wrapperInsertRule(PassRefPtr<StyleRuleBase> rule, unsigned index)
+bool StyleSheetContents::wrapperInsertRule(PassRefPtrWillBeRawPtr<StyleRuleBase> rule, unsigned index)
{
ASSERT(m_isMutable);
ASSERT_WITH_SECURITY_IMPLICATION(index <= ruleCount());
return parentSheet->loadCompleted();
StyleSheetContents* root = rootStyleSheet();
- for (unsigned i = 0; i < root->m_clients.size(); ++i) {
- if (!root->m_clients[i]->loadCompleted())
- return false;
- }
- return true;
+ return root->m_loadingClients.isEmpty();
}
void StyleSheetContents::checkLoaded()
// Avoid |this| being deleted by scripts that run via
// ScriptableDocumentParser::executeScriptsWaitingForResources().
// See https://bugs.webkit.org/show_bug.cgi?id=95106
- RefPtr<StyleSheetContents> protect(this);
+ RefPtrWillBeRawPtr<StyleSheetContents> protect(this);
StyleSheetContents* parentSheet = parentStyleSheet();
if (parentSheet) {
}
StyleSheetContents* root = rootStyleSheet();
- if (root->m_clients.isEmpty())
+ if (root->m_loadingClients.isEmpty())
return;
- Vector<CSSStyleSheet*> clients(root->m_clients);
- for (unsigned i = 0; i < clients.size(); ++i) {
- // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run via
- // ScriptableDocumentParser::executeScriptsWaitingForResources().
- RefPtr<CSSStyleSheet> protectClient(clients[i]);
-
- if (clients[i]->loadCompleted())
+ // Avoid |CSSSStyleSheet| and |ownerNode| being deleted by scripts that run via
+ // ScriptableDocumentParser::executeScriptsWaitingForResources(). Also protect
+ // the |CSSStyleSheet| from being deleted during iteration via the |sheetLoaded|
+ // method.
+ //
+ // When a sheet is loaded it is moved from the set of loading clients
+ // to the set of completed clients. We therefore need the copy in order to
+ // not modify the set while iterating it.
+ WillBeHeapVector<RefPtrWillBeMember<CSSStyleSheet> > loadingClients;
+ copyToVector(m_loadingClients, loadingClients);
+
+ for (unsigned i = 0; i < loadingClients.size(); ++i) {
+ if (loadingClients[i]->loadCompleted())
continue;
- RefPtr<Node> ownerNode = clients[i]->ownerNode();
- if (clients[i]->sheetLoaded())
- ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur);
+ // sheetLoaded might be invoked after its owner node is removed from document.
+ if (RefPtr<Node> ownerNode = loadingClients[i]->ownerNode()) {
+ if (loadingClients[i]->sheetLoaded())
+ ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur);
+ }
}
}
void StyleSheetContents::startLoadingDynamicSheet()
{
StyleSheetContents* root = rootStyleSheet();
- for (unsigned i = 0; i < root->m_clients.size(); ++i)
- root->m_clients[i]->startLoadingDynamicSheet();
+ for (ClientsIterator it = root->m_loadingClients.begin(); it != root->m_loadingClients.end(); ++it)
+ (*it)->startLoadingDynamicSheet();
+ // Copy the completed clients to a vector for iteration.
+ // startLoadingDynamicSheet will move the style sheet from the
+ // completed state to the loading state which modifies the set of
+ // completed clients. We therefore need the copy in order to not
+ // modify the set of completed clients while iterating it.
+ WillBeHeapVector<RawPtrWillBeMember<CSSStyleSheet> > completedClients;
+ copyToVector(root->m_completedClients, completedClients);
+ for (unsigned i = 0; i < completedClients.size(); ++i)
+ completedClients[i]->startLoadingDynamicSheet();
}
StyleSheetContents* StyleSheetContents::rootStyleSheet() const
bool StyleSheetContents::hasSingleOwnerNode() const
{
- StyleSheetContents* root = rootStyleSheet();
- if (root->m_clients.isEmpty())
- return false;
- return root->m_clients.size() == 1;
+ return rootStyleSheet()->hasOneClient();
}
Node* StyleSheetContents::singleOwnerNode() const
{
StyleSheetContents* root = rootStyleSheet();
- if (root->m_clients.isEmpty())
+ if (!root->hasOneClient())
return 0;
- ASSERT(root->m_clients.size() == 1);
- return root->m_clients[0]->ownerNode();
+ if (root->m_loadingClients.size())
+ return (*root->m_loadingClients.begin())->ownerNode();
+ return (*root->m_completedClients.begin())->ownerNode();
}
Document* StyleSheetContents::singleOwnerDocument() const
{
- Node* ownerNode = singleOwnerNode();
- return ownerNode ? &ownerNode->document() : 0;
+ StyleSheetContents* root = rootStyleSheet();
+ return root->clientSingleOwnerDocument();
}
KURL StyleSheetContents::completeURL(const String& url) const
return m_parserContext.completeURL(url);
}
-static bool childRulesHaveFailedOrCanceledSubresources(const Vector<RefPtr<StyleRuleBase> >& rules)
+static bool childRulesHaveFailedOrCanceledSubresources(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase> >& rules)
{
for (unsigned i = 0; i < rules.size(); ++i) {
const StyleRuleBase* rule = rules[i].get();
switch (rule->type()) {
case StyleRuleBase::Style:
- if (toStyleRule(rule)->properties()->hasFailedOrCanceledSubresources())
+ if (toStyleRule(rule)->properties().hasFailedOrCanceledSubresources())
return true;
break;
case StyleRuleBase::FontFace:
- if (toStyleRuleFontFace(rule)->properties()->hasFailedOrCanceledSubresources())
+ if (toStyleRuleFontFace(rule)->properties().hasFailedOrCanceledSubresources())
return true;
break;
case StyleRuleBase::Media:
return childRulesHaveFailedOrCanceledSubresources(m_childRules);
}
+Document* StyleSheetContents::clientSingleOwnerDocument() const
+{
+ if (!m_hasSingleOwnerDocument || clientSize() <= 0)
+ return 0;
+
+ if (m_loadingClients.size())
+ return (*m_loadingClients.begin())->ownerDocument();
+ return (*m_completedClients.begin())->ownerDocument();
+}
+
StyleSheetContents* StyleSheetContents::parentStyleSheet() const
{
return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0;
void StyleSheetContents::registerClient(CSSStyleSheet* sheet)
{
- ASSERT(!m_clients.contains(sheet));
- m_clients.append(sheet);
+ ASSERT(!m_loadingClients.contains(sheet) && !m_completedClients.contains(sheet));
+
+ // InspectorCSSAgent::buildObjectForRule creates CSSStyleSheet without any owner node.
+ if (!sheet->ownerDocument())
+ return;
+
+ if (Document* document = clientSingleOwnerDocument()) {
+ if (sheet->ownerDocument() != document)
+ m_hasSingleOwnerDocument = false;
+ }
+ m_loadingClients.add(sheet);
}
void StyleSheetContents::unregisterClient(CSSStyleSheet* sheet)
{
- size_t position = m_clients.find(sheet);
- ASSERT(position != kNotFound);
- m_clients.remove(position);
+ m_loadingClients.remove(sheet);
+ m_completedClients.remove(sheet);
+
+ if (!sheet->ownerDocument() || !m_loadingClients.isEmpty() || !m_completedClients.isEmpty())
+ return;
+
+ if (m_hasSingleOwnerDocument)
+ removeSheetFromCache(sheet->ownerDocument());
+ m_hasSingleOwnerDocument = true;
+}
+
+void StyleSheetContents::clientLoadCompleted(CSSStyleSheet* sheet)
+{
+ ASSERT(m_loadingClients.contains(sheet) || !sheet->ownerDocument());
+ m_loadingClients.remove(sheet);
+ // In m_ownerNode->sheetLoaded, the CSSStyleSheet might be detached.
+ // (i.e. clearOwnerNode was invoked.)
+ // In this case, we don't need to add the stylesheet to completed clients.
+ if (!sheet->ownerDocument())
+ return;
+ m_completedClients.add(sheet);
+}
+
+void StyleSheetContents::clientLoadStarted(CSSStyleSheet* sheet)
+{
+ ASSERT(m_completedClients.contains(sheet));
+ m_completedClients.remove(sheet);
+ m_loadingClients.add(sheet);
+}
+
+void StyleSheetContents::removeSheetFromCache(Document* document)
+{
+ ASSERT(document);
+ document->styleEngine()->removeSheet(this);
}
void StyleSheetContents::addedToMemoryCache()
return *m_ruleSet.get();
}
+static void clearResolvers(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >& clients)
+{
+ for (WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >::iterator it = clients.begin(); it != clients.end(); ++it) {
+ if (Document* document = (*it)->ownerDocument())
+ document->styleEngine()->clearResolver();
+ }
+}
+
void StyleSheetContents::clearRuleSet()
{
if (StyleSheetContents* parentSheet = parentStyleSheet())
// Clearing the ruleSet means we need to recreate the styleResolver data structures.
// See the StyleResolver calls in ScopedStyleResolver::addRulesFromSheet.
- for (size_t i = 0; i < m_clients.size(); ++i) {
- if (Document* document = m_clients[i]->ownerDocument())
- document->styleEngine()->clearResolver();
- }
+ clearResolvers(m_loadingClients);
+ clearResolvers(m_completedClients);
m_ruleSet.clear();
}
+static void removeFontFaceRules(WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >& clients, const StyleRuleFontFace* fontFaceRule)
+{
+ for (WillBeHeapHashSet<RawPtrWillBeWeakMember<CSSStyleSheet> >::iterator it = clients.begin(); it != clients.end(); ++it) {
+ if (Node* ownerNode = (*it)->ownerNode())
+ ownerNode->document().styleEngine()->removeFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >(1, fontFaceRule));
+ }
+}
+
void StyleSheetContents::notifyRemoveFontFaceRule(const StyleRuleFontFace* fontFaceRule)
{
StyleSheetContents* root = rootStyleSheet();
-
- for (unsigned i = 0; i < root->m_clients.size(); ++i) {
- if (Node* ownerNode = root->m_clients[0]->ownerNode())
- ownerNode->document().styleEngine()->removeFontFaceRules(Vector<const StyleRuleFontFace*>(1, fontFaceRule));
- }
+ removeFontFaceRules(root->m_loadingClients, fontFaceRule);
+ removeFontFaceRules(root->m_completedClients, fontFaceRule);
}
-static void findFontFaceRulesFromRules(const Vector<RefPtr<StyleRuleBase> >& rules, Vector<const StyleRuleFontFace*>& fontFaceRules)
+static void findFontFaceRulesFromRules(const WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase> >& rules, WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
{
for (unsigned i = 0; i < rules.size(); ++i) {
StyleRuleBase* rule = rules[i].get();
}
}
-void StyleSheetContents::findFontFaceRules(Vector<const StyleRuleFontFace*>& fontFaceRules)
+void StyleSheetContents::findFontFaceRules(WillBeHeapVector<RawPtrWillBeMember<const StyleRuleFontFace> >& fontFaceRules)
{
for (unsigned i = 0; i < m_importRules.size(); ++i) {
if (!m_importRules[i]->styleSheet())
findFontFaceRulesFromRules(childRules(), fontFaceRules);
}
-void StyleSheetContents::trace(Visitor*)
+void StyleSheetContents::trace(Visitor* visitor)
{
+ visitor->trace(m_ownerRule);
+ visitor->trace(m_importRules);
+ visitor->trace(m_childRules);
+ visitor->trace(m_loadingClients);
+ visitor->trace(m_completedClients);
+ visitor->trace(m_ruleSet);
}
}