Web Inspector: Native Memory Instrumentation: fix instrumentation for already instrum...
[WebKit-https.git] / Source / WebCore / css / StyleSheetContents.cpp
index 3eaa0da..6b7c0c5 100644 (file)
 #include "CSSStyleSheet.h"
 #include "CachedCSSStyleSheet.h"
 #include "Document.h"
-#include "MemoryInstrumentation.h"
+#include "MediaList.h"
 #include "Node.h"
 #include "SecurityOrigin.h"
 #include "StylePropertySet.h"
 #include "StyleRule.h"
 #include "StyleRuleImport.h"
+#include "WebCoreMemoryInstrumentation.h"
 #include <wtf/Deque.h>
+#include <wtf/MemoryInstrumentationHashMap.h>
+#include <wtf/MemoryInstrumentationVector.h>
 
 namespace WebCore {
 
@@ -54,9 +57,11 @@ unsigned StyleSheetContents::estimatedSizeInBytes() const
     return size;
 }
 
-StyleSheetContents::StyleSheetContents(const String& originalURL, const CSSParserContext& context)
-    : m_originalURL(originalURL)
+StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context)
+    : m_ownerRule(ownerRule)
+    , m_originalURL(originalURL)
     , m_loadCompleted(false)
+    , m_isUserStyleSheet(ownerRule && ownerRule->parentStyleSheet() && ownerRule->parentStyleSheet()->isUserStyleSheet())
     , m_hasSyntacticallyValidCSSHeader(true)
     , m_didLoadErrorOccur(false)
     , m_usesRemUnits(false)
@@ -68,6 +73,7 @@ StyleSheetContents::StyleSheetContents(const String& originalURL, const CSSParse
 
 StyleSheetContents::StyleSheetContents(const StyleSheetContents& o)
     : RefCounted<StyleSheetContents>()
+    , m_ownerRule(0)
     , m_originalURL(o.m_originalURL)
     , m_encodingFromCharsetRule(o.m_encodingFromCharsetRule)
     , m_importRules(o.m_importRules.size())
@@ -101,6 +107,9 @@ bool StyleSheetContents::isCacheable() const
     // FIXME: Support copying import rules.
     if (!m_importRules.isEmpty())
         return false;
+    // FIXME: Support cached stylesheets in import rules.
+    if (m_ownerRule)
+        return false;
     // This would require dealing with multiple clients for load callbacks.
     if (!m_loadCompleted)
         return false;
@@ -123,8 +132,17 @@ void StyleSheetContents::parserAppendRule(PassRefPtr<StyleRuleBase> rule)
         // Parser enforces that @import rules come before anything else except @charset.
         ASSERT(m_childRules.isEmpty());
         m_importRules.append(static_cast<StyleRuleImport*>(rule.get()));
+        m_importRules.last()->setParentStyleSheet(this);
+        m_importRules.last()->requestStyleSheet();
         return;
     }
+
+#if ENABLE(RESOLUTION_MEDIA_QUERY)
+    // Add warning message to inspector if dpi/dpcm values are used for screen media.
+    if (rule->isMediaRule())
+        reportMediaQueryWarningIfNeeded(singleOwnerDocument(), static_cast<StyleRuleMedia*>(rule.get())->mediaQueries());
+#endif
+
     m_childRules.append(rule);
 }
 
@@ -161,6 +179,10 @@ void StyleSheetContents::clearCharsetRule()
 
 void StyleSheetContents::clearRules()
 {
+    for (unsigned i = 0; i < m_importRules.size(); ++i) {
+        ASSERT(m_importRules.at(i)->parentStyleSheet() == this);
+        m_importRules[i]->clearParentStyleSheet();
+    }
     m_importRules.clear();
     m_childRules.clear();
     clearCharsetRule();
@@ -195,6 +217,9 @@ bool StyleSheetContents::wrapperInsertRule(PassRefPtr<StyleRuleBase> rule, unsig
         if (!rule->isImportRule())
             return false;
         m_importRules.insert(childVectorIndex, static_cast<StyleRuleImport*>(rule.get()));
+        m_importRules[childVectorIndex]->setParentStyleSheet(this);
+        m_importRules[childVectorIndex]->requestStyleSheet();
+        // FIXME: Stylesheet doesn't actually change meaningfully before the imported sheets are loaded.
         return true;
     }
     // Inserting @import rule after a non-import rule is not allowed.
@@ -220,6 +245,7 @@ void StyleSheetContents::wrapperDeleteRule(unsigned index)
         --childVectorIndex;
     }
     if (childVectorIndex < m_importRules.size()) {
+        m_importRules[childVectorIndex]->clearParentStyleSheet();
         m_importRules.remove(childVectorIndex);
         return;
     }
@@ -235,7 +261,7 @@ void StyleSheetContents::parserAddNamespace(const AtomicString& prefix, const At
     PrefixNamespaceURIMap::AddResult result = m_namespaces.add(prefix, uri);
     if (result.isNewEntry)
         return;
-    result.iterator->second = uri;
+    result.iterator->value = uri;
 }
 
 const AtomicString& StyleSheetContents::determineNamespace(const AtomicString& prefix)
@@ -247,25 +273,11 @@ const AtomicString& StyleSheetContents::determineNamespace(const AtomicString& p
     PrefixNamespaceURIMap::const_iterator it = m_namespaces.find(prefix);
     if (it == m_namespaces.end())
         return nullAtom;
-    return it->second;
-}
-
-void StyleSheetContents::requestImportedStyleSheets(CSSStyleSheet* rootSheet)
-{
-    ASSERT(!rootSheet->parentStyleSheet());
-    for (unsigned i = 0; i < m_importRules.size(); ++i)
-        m_importRules[i]->requestStyleSheet(rootSheet, parserContext());
+    return it->value;
 }
 
-void StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cachedStyleSheet, CSSStyleSheet* rootSheet)
+void StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cachedStyleSheet, const SecurityOrigin* securityOrigin)
 {
-    if (cachedStyleSheet->errorOccurred()) {
-        m_didLoadErrorOccur = true;
-        return;
-    }
-    Document* ownerDocument = rootSheet->ownerDocument();
-    if (!ownerDocument)
-        return;
     // Check to see if we should enforce the MIME type of the CSS resource in strict mode.
     // Running in iWeb 2 is one example of where we don't want to - <rdar://problem/6099748>
     bool enforceMIMEType = isStrictParserMode(m_parserContext.mode) && m_parserContext.enforcesCSSMIMETypeInNoQuirksMode;
@@ -279,7 +291,6 @@ void StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cached
     // to at least start with a syntactically valid CSS rule.
     // This prevents an attacker playing games by injecting CSS strings into HTML, XML, JSON, etc. etc.
     if (!hasValidMIMEType && !hasSyntacticallyValidCSSHeader()) {
-        const SecurityOrigin* securityOrigin = ownerDocument->securityOrigin();
         bool isCrossOriginCSS = !securityOrigin || !securityOrigin->canRequest(baseURL());
         if (isCrossOriginCSS) {
             clearRules();
@@ -288,18 +299,13 @@ void StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cached
     }
     if (m_parserContext.needsSiteSpecificQuirks && isStrictParserMode(m_parserContext.mode)) {
         // Work around <https://bugs.webkit.org/show_bug.cgi?id=28350>.
-        DEFINE_STATIC_LOCAL(const String, slashKHTMLFixesDotCss, ("/KHTMLFixes.css"));
-        DEFINE_STATIC_LOCAL(const String, mediaWikiKHTMLFixesStyleSheet, ("/* KHTML fix stylesheet */\n/* work around the horizontal scrollbars */\n#column-content { margin-left: 0; }\n\n"));
+        DEFINE_STATIC_LOCAL(const String, mediaWikiKHTMLFixesStyleSheet, (ASCIILiteral("/* KHTML fix stylesheet */\n/* work around the horizontal scrollbars */\n#column-content { margin-left: 0; }\n\n")));
         // There are two variants of KHTMLFixes.css. One is equal to mediaWikiKHTMLFixesStyleSheet,
         // while the other lacks the second trailing newline.
-        if (baseURL().string().endsWith(slashKHTMLFixesDotCss) && !sheetText.isNull() && mediaWikiKHTMLFixesStyleSheet.startsWith(sheetText)
-            && sheetText.length() >= mediaWikiKHTMLFixesStyleSheet.length() - 1) {
+        if (baseURL().string().endsWith("/KHTMLFixes.css") && !sheetText.isNull() && mediaWikiKHTMLFixesStyleSheet.startsWith(sheetText)
+            && sheetText.length() >= mediaWikiKHTMLFixesStyleSheet.length() - 1)
             clearRules();
-            return;
-        }
     }
-
-    requestImportedStyleSheets(rootSheet);
 }
 
 bool StyleSheetContents::parseString(const String& sheetText)
@@ -312,10 +318,6 @@ bool StyleSheetContents::parseStringAtLine(const String& sheetText, int startLin
     CSSParser p(parserContext());
     p.parseSheet(this, sheetText, startLineNumber);
 
-    if (!m_clients.isEmpty()) {
-        ASSERT(m_clients.size() == 1);
-        requestImportedStyleSheets(m_clients[0]);
-    }
     return true;
 }
 
@@ -328,68 +330,66 @@ bool StyleSheetContents::isLoading() const
     return false;
 }
 
-bool StyleSheetContents::checkImportedSheetLoadCompleted()
-{
-    for (unsigned i = 0; i < m_importRules.size(); ++i) {
-        StyleRuleImport* importRule = m_importRules[i].get();
-        if (importRule->isLoading())
-            return false;
-        if (importRule->styleSheet() && !importRule->styleSheet()->checkImportedSheetLoadCompleted())
-            return false;
-        if (importRule->hadLoadError())
-            m_didLoadErrorOccur = true;
-    }
-    m_loadCompleted = true;
-    return true;
-}
-
-void StyleSheetContents::checkLoadCompleted()
+void StyleSheetContents::checkLoaded()
 {
-    if (m_clients.isEmpty())
-        return;
-    if (!checkImportedSheetLoadCompleted())
+    if (isLoading())
         return;
 
-    ASSERT(hasOneClient());
-    ASSERT(!m_clients[0]->parentStyleSheet());
-    RefPtr<Node> ownerNode = m_clients[0]->ownerNode();
-    if (!ownerNode)
+    RefPtr<StyleSheetContents> protect(this);
+
+    // Avoid |this| being deleted by scripts that run via
+    // ScriptableDocumentParser::executeScriptsWaitingForStylesheets().
+    // See <rdar://problem/6622300>.
+    RefPtr<StyleSheetContents> protector(this);
+    StyleSheetContents* parentSheet = parentStyleSheet();
+    if (parentSheet) {
+        parentSheet->checkLoaded();
+        m_loadCompleted = true;
         return;
-    
+    }
+    RefPtr<Node> ownerNode = singleOwnerNode();
+    if (!ownerNode) {
+        m_loadCompleted = true;
+        return;
+    }
     m_loadCompleted = ownerNode->sheetLoaded();
     if (m_loadCompleted)
         ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur);
 }
 
-bool StyleSheetContents::getAncestors(const StyleRuleImport* importRule, Vector<const StyleSheetContents*>& result) const
+void StyleSheetContents::notifyLoadedSheet(const CachedCSSStyleSheet* sheet)
 {
-    result.append(this);
-    for (unsigned i = 0; i < m_importRules.size(); ++i) {
-        if (m_importRules[i] == importRule)
-            return true;
-    }
-    for (unsigned i = 0; i < m_importRules.size(); ++i) {
-        if (m_importRules[i]->styleSheet() && m_importRules[i]->styleSheet()->getAncestors(importRule, result))
-            return true;
-    }
-    result.removeLast();
-    return false;
+    ASSERT(sheet);
+    m_didLoadErrorOccur |= sheet->errorOccurred();
 }
 
-bool StyleSheetContents::hasImportCycle(const StyleRuleImport* importRule, const KURL& importURL, const KURL& documentBaseURL) const
+void StyleSheetContents::startLoadingDynamicSheet()
 {
-    Vector<const StyleSheetContents*> ancestors;
-    getAncestors(importRule, ancestors);
+    if (Node* owner = singleOwnerNode())
+        owner->startLoadingDynamicSheet();
+}
 
-    KURL parentBaseURL = documentBaseURL;
-    for (unsigned i = 0; i < ancestors.size(); ++i) {
-        if (equalIgnoringFragmentIdentifier(importURL, ancestors[i]->baseURL()))
-            return true;
-        if (equalIgnoringFragmentIdentifier(importURL, KURL(parentBaseURL, ancestors[i]->originalURL())))
-            return true;
-        parentBaseURL = ancestors[i]->baseURL();
-    }
-    return false;
+StyleSheetContents* StyleSheetContents::rootStyleSheet() const
+{
+    const StyleSheetContents* root = this;
+    while (root->parentStyleSheet())
+        root = root->parentStyleSheet();
+    return const_cast<StyleSheetContents*>(root);
+}
+
+Node* StyleSheetContents::singleOwnerNode() const
+{
+    StyleSheetContents* root = rootStyleSheet();
+    if (root->m_clients.isEmpty())
+        return 0;
+    ASSERT(root->m_clients.size() == 1);
+    return root->m_clients[0]->ownerNode();
+}
+
+Document* StyleSheetContents::singleOwnerDocument() const
+{
+    Node* ownerNode = singleOwnerNode();
+    return ownerNode ? ownerNode->document() : 0;
 }
 
 KURL StyleSheetContents::completeURL(const String& url) const
@@ -443,6 +443,12 @@ static bool childRulesHaveFailedOrCanceledSubresources(const Vector<RefPtr<Style
             if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleRegion*>(rule)->childRules()))
                 return true;
             break;
+#if ENABLE(SHADOW_DOM)
+        case StyleRuleBase::Host:
+            if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleHost*>(rule)->childRules()))
+                return true;
+            break;
+#endif
         case StyleRuleBase::Import:
             ASSERT_NOT_REACHED();
         case StyleRuleBase::Page:
@@ -450,6 +456,9 @@ static bool childRulesHaveFailedOrCanceledSubresources(const Vector<RefPtr<Style
         case StyleRuleBase::Unknown:
         case StyleRuleBase::Charset:
         case StyleRuleBase::Keyframe:
+#if ENABLE(CSS_DEVICE_ADAPTATION)
+        case StyleRuleBase::Viewport:
+#endif
             break;
         }
     }
@@ -462,6 +471,11 @@ bool StyleSheetContents::hasFailedOrCanceledSubresources() const
     return childRulesHaveFailedOrCanceledSubresources(m_childRules);
 }
 
+StyleSheetContents* StyleSheetContents::parentStyleSheet() const
+{
+    return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0;
+}
+
 void StyleSheetContents::registerClient(CSSStyleSheet* sheet)
 {
     ASSERT(!m_clients.contains(sheet));
@@ -489,15 +503,23 @@ void StyleSheetContents::removedFromMemoryCache()
     m_isInMemoryCache = false;
 }
 
+void StyleSheetContents::shrinkToFit()
+{
+    m_importRules.shrinkToFit();
+    m_childRules.shrinkToFit();
+}
+
 void StyleSheetContents::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 {
-    MemoryClassInfo info(memoryObjectInfo, this, MemoryInstrumentation::CSS);
-    info.addInstrumentedMember(m_originalURL);
-    info.addInstrumentedMember(m_encodingFromCharsetRule);
-    info.addVector(m_importRules);
-    info.addInstrumentedVector(m_childRules);
-    info.addHashMap(m_namespaces);
-    info.addVector(m_clients);
+    MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS);
+    info.addMember(m_ownerRule);
+    info.addMember(m_originalURL);
+    info.addMember(m_encodingFromCharsetRule);
+    info.addMember(m_importRules);
+    info.addMember(m_childRules);
+    info.addMember(m_namespaces);
+    info.addMember(m_parserContext);
+    info.addMember(m_clients);
 }
 
 }