Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / StyleSheetContents.cpp
index 87e4144..5b72384 100644 (file)
@@ -38,8 +38,6 @@
 
 namespace WebCore {
 
-DEFINE_GC_INFO(StyleSheetContents);
-
 // Rough size estimate for the memory cache.
 unsigned StyleSheetContents::estimatedSizeInBytes() const
 {
@@ -68,12 +66,13 @@ StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String&
     , 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())
@@ -86,6 +85,7 @@ StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
     , m_isInMemoryCache(false)
     , m_hasFontFaceRule(o.m_hasFontFaceRule)
     , m_hasMediaQueries(o.m_hasMediaQueries)
+    , m_hasSingleOwnerDocument(true)
     , m_parserContext(o.m_parserContext)
 {
     ASSERT(o.isCacheable());
@@ -99,19 +99,25 @@ StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
 
 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.
@@ -137,15 +143,7 @@ bool StyleSheetContents::maybeCacheable() const
     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()) {
@@ -225,7 +223,7 @@ void StyleSheetContents::parserSetEncodingFromCharsetRule(const String& encoding
     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());
@@ -374,11 +372,7 @@ bool StyleSheetContents::loadCompleted() const
         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()
@@ -389,7 +383,7 @@ 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) {
@@ -398,21 +392,29 @@ void StyleSheetContents::checkLoaded()
     }
 
     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);
+        }
     }
 }
 
@@ -429,8 +431,17 @@ void StyleSheetContents::notifyLoadedSheet(const CSSStyleSheetResource* sheet)
 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
@@ -443,25 +454,23 @@ 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
@@ -470,17 +479,17 @@ 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:
@@ -509,6 +518,16 @@ bool StyleSheetContents::hasFailedOrCanceledSubresources() const
     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;
@@ -516,15 +535,55 @@ StyleSheetContents* StyleSheetContents::parentStyleSheet() const
 
 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()
@@ -556,6 +615,14 @@ RuleSet& StyleSheetContents::ensureRuleSet(const MediaQueryEvaluator& medium, Ad
     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())
@@ -569,24 +636,27 @@ void StyleSheetContents::clearRuleSet()
 
     // 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();
@@ -602,7 +672,7 @@ static void findFontFaceRulesFromRules(const Vector<RefPtr<StyleRuleBase> >& rul
     }
 }
 
-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())
@@ -613,8 +683,14 @@ void StyleSheetContents::findFontFaceRules(Vector<const StyleRuleFontFace*>& fon
     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);
 }
 
 }