Title: [126717] trunk/Source/WebCore
Revision
126717
Author
[email protected]
Date
2012-08-26 16:48:39 -0700 (Sun, 26 Aug 2012)

Log Message

Remove parent pointer from StyleSheetContents and StyleRuleImport
https://bugs.webkit.org/show_bug.cgi?id=94926

Reviewed by Andreas Kling.

To be able to cache and share @imported stylesheets in the future there must not be any parent
pointers in the stylesheet tree.

Parent pointers are used during loading to invoke load completion callbacks and for
accessing document context information (like the security origin). They are not used after
the sheet load is complete. Instead of keeping the parent pointers around indefinitely as part of the 
stylesheet data structure we just keep a pointer to the root CSSStyleSheet for the duration of the load.
        
This patch doesn't enable any new caching or generally change the behavior.

* css/CSSStyleSheet.cpp:
(WebCore::CSSStyleSheet::insertRule):
(WebCore::CSSStyleSheet::rootStyleSheet):
(WebCore):
(WebCore::CSSStyleSheet::ownerDocument):
* css/CSSStyleSheet.h:
(CSSStyleSheet):
* css/StyleRuleImport.cpp:
(WebCore::StyleRuleImport::LoadContext::LoadContext):
        
    Simplify by making StyleRuleImport CachedStyleSheetClient directly. LoadContext contains
    fields that can be thrown away after load completes.

(WebCore):
(WebCore::StyleRuleImport::StyleRuleImport):
(WebCore::StyleRuleImport::~StyleRuleImport):
(WebCore::StyleRuleImport::setCSSStyleSheet):
(WebCore::StyleRuleImport::isLoading):
(WebCore::StyleRuleImport::hadLoadError):
(WebCore::StyleRuleImport::requestStyleSheet):
* css/StyleRuleImport.h:
(StyleRuleImport):
(LoadContext):
* css/StyleSheetContents.cpp:
(WebCore::StyleSheetContents::StyleSheetContents):
        
    Remove now unnecessary constructor. 

(WebCore::StyleSheetContents::isCacheable):
(WebCore::StyleSheetContents::parserAppendRule):
(WebCore::StyleSheetContents::clearRules):
(WebCore::StyleSheetContents::wrapperInsertRule):
(WebCore::StyleSheetContents::wrapperDeleteRule):
(WebCore::StyleSheetContents::requestImportedStyleSheets):
(WebCore):
(WebCore::StyleSheetContents::parseAuthorStyleSheet):
(WebCore::StyleSheetContents::parseStringAtLine):
(WebCore::StyleSheetContents::checkImportedSheetLoadCompleted):
(WebCore::StyleSheetContents::checkLoadCompleted):
(WebCore::StyleSheetContents::getAncestors):
(WebCore::StyleSheetContents::hasImportCycle):
        
    Move the cycle checking to the root stylesheet so we don't need to pass the entire chain around.
    The extra work here is unlikely to cause problems, massive import trees don't really occur in
    practice.

* css/StyleSheetContents.h:
(WebCore::StyleSheetContents::create):
(StyleSheetContents):
* dom/ProcessingInstruction.cpp:
(WebCore::ProcessingInstruction::parseStyleSheet):
* dom/StyleElement.cpp:
(WebCore::StyleElement::createSheet):
* html/HTMLLinkElement.cpp:
(WebCore::HTMLLinkElement::setCSSStyleSheet):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (126716 => 126717)


--- trunk/Source/WebCore/ChangeLog	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/ChangeLog	2012-08-26 23:48:39 UTC (rev 126717)
@@ -1,3 +1,76 @@
+2012-08-26  Antti Koivisto  <[email protected]>
+
+        Remove parent pointer from StyleSheetContents and StyleRuleImport
+        https://bugs.webkit.org/show_bug.cgi?id=94926
+
+        Reviewed by Andreas Kling.
+
+        To be able to cache and share @imported stylesheets in the future there must not be any parent
+        pointers in the stylesheet tree.
+
+        Parent pointers are used during loading to invoke load completion callbacks and for
+        accessing document context information (like the security origin). They are not used after
+        the sheet load is complete. Instead of keeping the parent pointers around indefinitely as part of the 
+        stylesheet data structure we just keep a pointer to the root CSSStyleSheet for the duration of the load.
+        
+        This patch doesn't enable any new caching or generally change the behavior.
+
+        * css/CSSStyleSheet.cpp:
+        (WebCore::CSSStyleSheet::insertRule):
+        (WebCore::CSSStyleSheet::rootStyleSheet):
+        (WebCore):
+        (WebCore::CSSStyleSheet::ownerDocument):
+        * css/CSSStyleSheet.h:
+        (CSSStyleSheet):
+        * css/StyleRuleImport.cpp:
+        (WebCore::StyleRuleImport::LoadContext::LoadContext):
+        
+            Simplify by making StyleRuleImport CachedStyleSheetClient directly. LoadContext contains
+            fields that can be thrown away after load completes.
+
+        (WebCore):
+        (WebCore::StyleRuleImport::StyleRuleImport):
+        (WebCore::StyleRuleImport::~StyleRuleImport):
+        (WebCore::StyleRuleImport::setCSSStyleSheet):
+        (WebCore::StyleRuleImport::isLoading):
+        (WebCore::StyleRuleImport::hadLoadError):
+        (WebCore::StyleRuleImport::requestStyleSheet):
+        * css/StyleRuleImport.h:
+        (StyleRuleImport):
+        (LoadContext):
+        * css/StyleSheetContents.cpp:
+        (WebCore::StyleSheetContents::StyleSheetContents):
+        
+            Remove now unnecessary constructor. 
+
+        (WebCore::StyleSheetContents::isCacheable):
+        (WebCore::StyleSheetContents::parserAppendRule):
+        (WebCore::StyleSheetContents::clearRules):
+        (WebCore::StyleSheetContents::wrapperInsertRule):
+        (WebCore::StyleSheetContents::wrapperDeleteRule):
+        (WebCore::StyleSheetContents::requestImportedStyleSheets):
+        (WebCore):
+        (WebCore::StyleSheetContents::parseAuthorStyleSheet):
+        (WebCore::StyleSheetContents::parseStringAtLine):
+        (WebCore::StyleSheetContents::checkImportedSheetLoadCompleted):
+        (WebCore::StyleSheetContents::checkLoadCompleted):
+        (WebCore::StyleSheetContents::getAncestors):
+        (WebCore::StyleSheetContents::hasImportCycle):
+        
+            Move the cycle checking to the root stylesheet so we don't need to pass the entire chain around.
+            The extra work here is unlikely to cause problems, massive import trees don't really occur in
+            practice.
+
+        * css/StyleSheetContents.h:
+        (WebCore::StyleSheetContents::create):
+        (StyleSheetContents):
+        * dom/ProcessingInstruction.cpp:
+        (WebCore::ProcessingInstruction::parseStyleSheet):
+        * dom/StyleElement.cpp:
+        (WebCore::StyleElement::createSheet):
+        * html/HTMLLinkElement.cpp:
+        (WebCore::HTMLLinkElement::setCSSStyleSheet):
+
 2012-08-26  Andreas Kling  <[email protected]>
 
         Avoid pointless string/number round-trip in applyRelativeFontStyleChange().

Modified: trunk/Source/WebCore/css/CSSStyleSheet.cpp (126716 => 126717)


--- trunk/Source/WebCore/css/CSSStyleSheet.cpp	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/css/CSSStyleSheet.cpp	2012-08-26 23:48:39 UTC (rev 126717)
@@ -37,6 +37,7 @@
 #include "SVGNames.h"
 #include "SecurityOrigin.h"
 #include "StyleRule.h"
+#include "StyleRuleImport.h"
 #include "StyleSheetContents.h"
 #include <wtf/text/StringBuilder.h>
 
@@ -283,7 +284,10 @@
     if (!success) {
         ec = HIERARCHY_REQUEST_ERR;
         return 0;
-    }        
+    }
+    if (rule->isImportRule())
+        static_cast<StyleRuleImport*>(rule.get())->requestStyleSheet(rootStyleSheet(), m_contents->parserContext());
+
     if (!m_childRuleCSSOMWrappers.isEmpty())
         m_childRuleCSSOMWrappers.insert(index, RefPtr<CSSRule>());
 
@@ -370,11 +374,17 @@
     return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0; 
 }
 
-Document* CSSStyleSheet::ownerDocument() const
+CSSStyleSheet* CSSStyleSheet::rootStyleSheet() const
 {
     const CSSStyleSheet* root = this;
     while (root->parentStyleSheet())
         root = root->parentStyleSheet();
+    return const_cast<CSSStyleSheet*>(root);
+}
+
+Document* CSSStyleSheet::ownerDocument() const
+{
+    const CSSStyleSheet* root = rootStyleSheet();
     return root->ownerNode() ? root->ownerNode()->document() : 0;
 }
 

Modified: trunk/Source/WebCore/css/CSSStyleSheet.h (126716 => 126717)


--- trunk/Source/WebCore/css/CSSStyleSheet.h	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/css/CSSStyleSheet.h	2012-08-26 23:48:39 UTC (rev 126717)
@@ -81,6 +81,7 @@
     virtual bool isLoading() const OVERRIDE;
     
     void clearOwnerRule() { m_ownerRule = 0; }
+    CSSStyleSheet* rootStyleSheet() const;
     Document* ownerDocument() const;
     MediaQuerySet* mediaQueries() const { return m_mediaQueries.get(); }
     void setMediaQueries(PassRefPtr<MediaQuerySet>);

Modified: trunk/Source/WebCore/css/StyleRuleImport.cpp (126716 => 126717)


--- trunk/Source/WebCore/css/StyleRuleImport.cpp	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/css/StyleRuleImport.cpp	2012-08-26 23:48:39 UTC (rev 126717)
@@ -32,6 +32,12 @@
 
 namespace WebCore {
 
+StyleRuleImport::LoadContext::LoadContext(CSSStyleSheet* rootStyleSheet, const CSSParserContext& parentParserContext)
+    : rootStyleSheet(rootStyleSheet)
+    , parentParserContext(parentParserContext)
+{
+}
+
 PassRefPtr<StyleRuleImport> StyleRuleImport::create(const String& href, PassRefPtr<MediaQuerySet> media)
 {
     return adoptRef(new StyleRuleImport(href, media));
@@ -39,12 +45,9 @@
 
 StyleRuleImport::StyleRuleImport(const String& href, PassRefPtr<MediaQuerySet> media)
     : StyleRuleBase(Import, 0)
-    , m_parentStyleSheet(0)
-    , m_styleSheetClient(this)
     , m_strHref(href)
     , m_mediaQueries(media)
     , m_cachedSheet(0)
-    , m_loading(false)
 {
     if (!m_mediaQueries)
         m_mediaQueries = MediaQuerySet::create(String());
@@ -52,83 +55,76 @@
 
 StyleRuleImport::~StyleRuleImport()
 {
-    if (m_styleSheet)
-        m_styleSheet->clearOwnerRule();
     if (m_cachedSheet)
-        m_cachedSheet->removeClient(&m_styleSheetClient);
+        m_cachedSheet->removeClient(this);
 }
 
-void StyleRuleImport::setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* cachedStyleSheet)
+void StyleRuleImport::setCSSStyleSheet(const String& url, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet*)
 {
-    if (m_styleSheet)
-        m_styleSheet->clearOwnerRule();
+    ASSERT(m_loadContext);
+    ASSERT(!m_styleSheet);
+    ASSERT(m_cachedSheet);
 
-    CSSParserContext context = m_parentStyleSheet ? m_parentStyleSheet->parserContext() : CSSStrictMode;
-    context.charset = charset;
+    OwnPtr<LoadContext> loadContext = m_loadContext.release();
+
+    CSSParserContext parserContext = loadContext->parentParserContext;
     if (!baseURL.isNull())
-        context.baseURL = baseURL;
+        parserContext.baseURL = baseURL;
+    parserContext.charset = charset;
 
-    m_styleSheet = StyleSheetContents::create(this, href, context);
+    m_styleSheet = StyleSheetContents::create(url, parserContext);
+    m_styleSheet->parseAuthorStyleSheet(m_cachedSheet.get(), loadContext->rootStyleSheet.get());
 
-    Document* document = m_parentStyleSheet ? m_parentStyleSheet->singleOwnerDocument() : 0;
-    m_styleSheet->parseAuthorStyleSheet(cachedStyleSheet, document ? document->securityOrigin() : 0);
-
-    m_loading = false;
-
-    if (m_parentStyleSheet) {
-        m_parentStyleSheet->notifyLoadedSheet(cachedStyleSheet);
-        m_parentStyleSheet->checkLoaded();
-    }
+    loadContext->rootStyleSheet->contents()->checkLoadCompleted();
 }
 
 bool StyleRuleImport::isLoading() const
 {
-    return m_loading || (m_styleSheet && m_styleSheet->isLoading());
+    return m_loadContext || (m_styleSheet && m_styleSheet->isLoading());
 }
 
-void StyleRuleImport::requestStyleSheet()
+bool StyleRuleImport::hadLoadError() const
 {
-    if (!m_parentStyleSheet)
-        return;
-    Document* document = m_parentStyleSheet->singleOwnerDocument();
-    if (!document)
-        return;
+    return m_cachedSheet && m_cachedSheet->errorOccurred();
+}
 
-    CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader();
-    if (!cachedResourceLoader)
+void StyleRuleImport::requestStyleSheet(CSSStyleSheet* rootSheet, const CSSParserContext& parserContext)
+{
+    ASSERT(!rootSheet->parentStyleSheet());
+    ASSERT(!m_cachedSheet);
+
+    Node* ownerNode = rootSheet->ownerNode();
+    if (!ownerNode)
         return;
+    Document* document = ownerNode->document();
 
-    KURL absURL;
-    if (!m_parentStyleSheet->baseURL().isNull())
-        // use parent styleheet's URL as the base URL
-        absURL = KURL(m_parentStyleSheet->baseURL(), m_strHref);
+    KURL resolvedURL;
+    if (!parserContext.baseURL.isNull())
+        resolvedURL = KURL(parserContext.baseURL, m_strHref);
     else
-        absURL = document->completeURL(m_strHref);
+        resolvedURL = document->completeURL(m_strHref);
 
-    // Check for a cycle in our import chain.  If we encounter a stylesheet
-    // in our parent chain with the same URL, then just bail.
-    StyleSheetContents* rootSheet = m_parentStyleSheet;
-    for (StyleSheetContents* sheet = m_parentStyleSheet; sheet; sheet = sheet->parentStyleSheet()) {
-        if (equalIgnoringFragmentIdentifier(absURL, sheet->baseURL())
-            || equalIgnoringFragmentIdentifier(absURL, document->completeURL(sheet->originalURL())))
-            return;
-        rootSheet = sheet;
-    }
+    StyleSheetContents* rootSheetContents = rootSheet->contents();
+    if (rootSheetContents->hasImportCycle(this, resolvedURL, document->baseURL()))
+        return;
 
-    ResourceRequest request(absURL);
-    if (m_parentStyleSheet->isUserStyleSheet())
-        m_cachedSheet = cachedResourceLoader->requestUserCSSStyleSheet(request, m_parentStyleSheet->charset());
+    ResourceRequest request(resolvedURL);
+    CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader();
+    if (rootSheetContents->isUserStyleSheet())
+        m_cachedSheet = cachedResourceLoader->requestUserCSSStyleSheet(request, parserContext.charset);
     else
-        m_cachedSheet = cachedResourceLoader->requestCSSStyleSheet(request, m_parentStyleSheet->charset());
-    if (m_cachedSheet) {
-        // if the import rule is issued dynamically, the sheet may be
-        // removed from the pending sheet count, so let the doc know
-        // the sheet being imported is pending.
-        if (m_parentStyleSheet && m_parentStyleSheet->loadCompleted() && rootSheet == m_parentStyleSheet)
-            m_parentStyleSheet->startLoadingDynamicSheet();
-        m_loading = true;
-        m_cachedSheet->addClient(&m_styleSheetClient);
-    }
+        m_cachedSheet = cachedResourceLoader->requestCSSStyleSheet(request, parserContext.charset);
+
+    if (!m_cachedSheet)
+        return;
+    // if the import rule is issued dynamically, the sheet may be
+    // removed from the pending sheet count, so let the doc know
+    // the sheet being imported is pending.
+    if (rootSheetContents->loadCompleted())
+        ownerNode->startLoadingDynamicSheet();
+
+    m_loadContext = adoptPtr(new LoadContext(rootSheet, parserContext));
+    m_cachedSheet->addClient(this);
 }
 
 void StyleRuleImport::reportDescendantMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const

Modified: trunk/Source/WebCore/css/StyleRuleImport.h (126716 => 126717)


--- trunk/Source/WebCore/css/StyleRuleImport.h	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/css/StyleRuleImport.h	2012-08-26 23:48:39 UTC (rev 126717)
@@ -22,6 +22,7 @@
 #ifndef StyleRuleImport_h
 #define StyleRuleImport_h
 
+#include "CSSParserMode.h"
 #include "CachedResourceHandle.h"
 #include "CachedStyleSheetClient.h"
 #include "StyleRule.h"
@@ -33,54 +34,39 @@
 class MemoryObjectInfo;
 class StyleSheetContents;
 
-class StyleRuleImport : public StyleRuleBase {
+class StyleRuleImport : public StyleRuleBase, public CachedStyleSheetClient {
 public:
     static PassRefPtr<StyleRuleImport> create(const String& href, PassRefPtr<MediaQuerySet>);
 
-    ~StyleRuleImport();
-    
-    StyleSheetContents* parentStyleSheet() const { return m_parentStyleSheet; }
-    void setParentStyleSheet(StyleSheetContents* sheet) { ASSERT(sheet); m_parentStyleSheet = sheet; }
-    void clearParentStyleSheet() { m_parentStyleSheet = 0; }
+    virtual ~StyleRuleImport();
 
     String href() const { return m_strHref; }
     StyleSheetContents* styleSheet() const { return m_styleSheet.get(); }
 
     bool isLoading() const;
+    bool hadLoadError() const;
     MediaQuerySet* mediaQueries() { return m_mediaQueries.get(); }
 
-    void requestStyleSheet();
+    void requestStyleSheet(CSSStyleSheet* rootSheet, const CSSParserContext&);
 
     void reportDescendantMemoryUsage(MemoryObjectInfo*) const;
 
 private:
-    // NOTE: We put the CachedStyleSheetClient in a member instead of inheriting from it
-    // to avoid adding a vptr to StyleRuleImport.
-    class ImportedStyleSheetClient : public CachedStyleSheetClient {
-    public:
-        ImportedStyleSheetClient(StyleRuleImport* ownerRule) : m_ownerRule(ownerRule) { }
-        virtual ~ImportedStyleSheetClient() { }
-        virtual void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet* sheet)
-        {
-            m_ownerRule->setCSSStyleSheet(href, baseURL, charset, sheet);
-        }
-    private:
-        StyleRuleImport* m_ownerRule;
-    };
-
-    void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet*);
-    friend class ImportedStyleSheetClient;
-
     StyleRuleImport(const String& href, PassRefPtr<MediaQuerySet>);
 
-    StyleSheetContents* m_parentStyleSheet;
+    virtual void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CachedCSSStyleSheet*);
 
-    ImportedStyleSheetClient m_styleSheetClient;
     String m_strHref;
     RefPtr<MediaQuerySet> m_mediaQueries;
     RefPtr<StyleSheetContents> m_styleSheet;
+
     CachedResourceHandle<CachedCSSStyleSheet> m_cachedSheet;
-    bool m_loading;
+    struct LoadContext {
+        LoadContext(CSSStyleSheet* rootStyleSheet, const CSSParserContext& parentParserContext);
+        RefPtr<CSSStyleSheet> rootStyleSheet;
+        CSSParserContext parentParserContext;
+    };
+    OwnPtr<LoadContext> m_loadContext;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/css/StyleSheetContents.cpp (126716 => 126717)


--- trunk/Source/WebCore/css/StyleSheetContents.cpp	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/css/StyleSheetContents.cpp	2012-08-26 23:48:39 UTC (rev 126717)
@@ -54,11 +54,9 @@
     return size;
 }
 
-StyleSheetContents::StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context)
-    : m_ownerRule(ownerRule)
-    , m_originalURL(originalURL)
+StyleSheetContents::StyleSheetContents(const String& originalURL, const CSSParserContext& context)
+    : m_originalURL(originalURL)
     , m_loadCompleted(false)
-    , m_isUserStyleSheet(ownerRule && ownerRule->parentStyleSheet() && ownerRule->parentStyleSheet()->isUserStyleSheet())
     , m_hasSyntacticallyValidCSSHeader(true)
     , m_didLoadErrorOccur(false)
     , m_usesRemUnits(false)
@@ -70,7 +68,6 @@
 
 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())
@@ -104,9 +101,6 @@
     // 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;
@@ -129,8 +123,6 @@
         // 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;
     }
     m_childRules.append(rule);
@@ -169,10 +161,6 @@
 
 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();
@@ -207,9 +195,6 @@
         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.
@@ -235,7 +220,6 @@
         --childVectorIndex;
     }
     if (childVectorIndex < m_importRules.size()) {
-        m_importRules[childVectorIndex]->clearParentStyleSheet();
         m_importRules.remove(childVectorIndex);
         return;
     }
@@ -266,8 +250,22 @@
     return it->second;
 }
 
-void StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cachedStyleSheet, const SecurityOrigin* securityOrigin)
+void StyleSheetContents::requestImportedStyleSheets(CSSStyleSheet* rootSheet)
 {
+    ASSERT(!rootSheet->parentStyleSheet());
+    for (unsigned i = 0; i < m_importRules.size(); ++i)
+        m_importRules[i]->requestStyleSheet(rootSheet, parserContext());
+}
+
+void StyleSheetContents::parseAuthorStyleSheet(const CachedCSSStyleSheet* cachedStyleSheet, CSSStyleSheet* rootSheet)
+{
+    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;
@@ -281,6 +279,7 @@
     // 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();
@@ -294,9 +293,13 @@
         // 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)
+            && sheetText.length() >= mediaWikiKHTMLFixesStyleSheet.length() - 1) {
             clearRules();
+            return;
+        }
     }
+
+    requestImportedStyleSheets(rootSheet);
 }
 
 bool StyleSheetContents::parseString(const String& sheetText)
@@ -309,6 +312,10 @@
     CSSParser p(parserContext());
     p.parseSheet(this, sheetText, startLineNumber);
 
+    if (!m_clients.isEmpty()) {
+        ASSERT(m_clients.size() == 1);
+        requestImportedStyleSheets(m_clients[0]);
+    }
     return true;
 }
 
@@ -321,66 +328,70 @@
     return false;
 }
 
-void StyleSheetContents::checkLoaded()
+bool StyleSheetContents::checkImportedSheetLoadCompleted()
 {
-    if (isLoading())
+    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()
+{
+    if (m_clients.isEmpty())
         return;
+    if (!checkImportedSheetLoadCompleted())
+        return;
 
-    // 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;
+    ASSERT(hasOneClient());
+    ASSERT(!m_clients[0]->parentStyleSheet());
+    RefPtr<Node> ownerNode = m_clients[0]->ownerNode();
+    if (!ownerNode)
         return;
-    }
-    RefPtr<Node> ownerNode = singleOwnerNode();
-    if (!ownerNode) {
-        m_loadCompleted = true;
-        return;
-    }
+    
     m_loadCompleted = ownerNode->sheetLoaded();
     if (m_loadCompleted)
         ownerNode->notifyLoadedSheetAndAllCriticalSubresources(m_didLoadErrorOccur);
 }
 
-void StyleSheetContents::notifyLoadedSheet(const CachedCSSStyleSheet* sheet)
+bool StyleSheetContents::getAncestors(const StyleRuleImport* importRule, Vector<const StyleSheetContents*>& result) const
 {
-    ASSERT(sheet);
-    m_didLoadErrorOccur |= sheet->errorOccurred();
+    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;
 }
 
-void StyleSheetContents::startLoadingDynamicSheet()
+bool StyleSheetContents::hasImportCycle(const StyleRuleImport* importRule, const KURL& importURL, const KURL& documentBaseURL) const
 {
-    if (Node* owner = singleOwnerNode())
-        owner->startLoadingDynamicSheet();
-}
+    Vector<const StyleSheetContents*> ancestors;
+    getAncestors(importRule, ancestors);
 
-StyleSheetContents* StyleSheetContents::rootStyleSheet() const
-{
-    const StyleSheetContents* root = this;
-    while (root->parentStyleSheet())
-        root = root->parentStyleSheet();
-    return const_cast<StyleSheetContents*>(root);
+    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;
 }
 
-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
 {
     return CSSParser::completeURL(m_parserContext, url);
@@ -451,11 +462,6 @@
     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));

Modified: trunk/Source/WebCore/css/StyleSheetContents.h (126716 => 126717)


--- trunk/Source/WebCore/css/StyleSheetContents.h	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/css/StyleSheetContents.h	2012-08-26 23:48:39 UTC (rev 126717)
@@ -44,16 +44,12 @@
 public:
     static PassRefPtr<StyleSheetContents> create(const CSSParserContext& context = CSSParserContext(CSSStrictMode))
     {
-        return adoptRef(new StyleSheetContents(0, String(), context));
+        return adoptRef(new StyleSheetContents(String(), context));
     }
     static PassRefPtr<StyleSheetContents> create(const String& originalURL, const CSSParserContext& context)
     {
-        return adoptRef(new StyleSheetContents(0, originalURL, context));
+        return adoptRef(new StyleSheetContents(originalURL, context));
     }
-    static PassRefPtr<StyleSheetContents> create(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext& context)
-    {
-        return adoptRef(new StyleSheetContents(ownerRule, originalURL, context));
-    }
 
     ~StyleSheetContents();
     
@@ -61,7 +57,7 @@
 
     const AtomicString& determineNamespace(const AtomicString& prefix);
 
-    void parseAuthorStyleSheet(const CachedCSSStyleSheet*, const SecurityOrigin*);
+    void parseAuthorStyleSheet(const CachedCSSStyleSheet*, CSSStyleSheet* rootSheet);
     bool parseString(const String&);
     bool parseStringAtLine(const String&, int startLineNumber);
 
@@ -69,13 +65,8 @@
 
     bool isLoading() const;
 
-    void checkLoaded();
-    void startLoadingDynamicSheet();
+    void checkLoadCompleted();
 
-    StyleSheetContents* rootStyleSheet() const;
-    Node* singleOwnerNode() const;
-    Document* singleOwnerDocument() const;
-
     const String& charset() const { return m_parserContext.charset; }
 
     bool loadCompleted() const { return m_loadCompleted; }
@@ -102,12 +93,8 @@
     const Vector<RefPtr<StyleRuleBase> >& childRules() const { return m_childRules; }
     const Vector<RefPtr<StyleRuleImport> >& importRules() const { return m_importRules; }
 
-    void notifyLoadedSheet(const CachedCSSStyleSheet*);
-    
-    StyleSheetContents* parentStyleSheet() const;
-    StyleRuleImport* ownerRule() const { return m_ownerRule; }
-    void clearOwnerRule() { m_ownerRule = 0; }
-    
+    bool hasImportCycle(const StyleRuleImport* importRule, const KURL& importURL, const KURL& documentBaseURL) const;
+
     // Note that href is the URL that started the redirect chain that led to
     // this style sheet. This property probably isn't useful for much except
     // the _javascript_ binding (which needs to use this value for security).
@@ -124,6 +111,8 @@
     bool wrapperInsertRule(PassRefPtr<StyleRuleBase>, unsigned index);
     void wrapperDeleteRule(unsigned index);
 
+    void requestImportedStyleSheets(CSSStyleSheet* rootSheet);
+
     PassRefPtr<StyleSheetContents> copy() const { return adoptRef(new StyleSheetContents(*this)); }
 
     void registerClient(CSSStyleSheet*);
@@ -140,12 +129,13 @@
     void reportMemoryUsage(MemoryObjectInfo*) const;
 
 private:
-    StyleSheetContents(StyleRuleImport* ownerRule, const String& originalURL, const CSSParserContext&);
+    StyleSheetContents(const String& originalURL, const CSSParserContext&);
     StyleSheetContents(const StyleSheetContents&);
 
     void clearCharsetRule();
 
-    StyleRuleImport* m_ownerRule;
+    bool checkImportedSheetLoadCompleted();
+    bool getAncestors(const StyleRuleImport*, Vector<const StyleSheetContents*>& result) const;
 
     String m_originalURL;
 

Modified: trunk/Source/WebCore/dom/ProcessingInstruction.cpp (126716 => 126717)


--- trunk/Source/WebCore/dom/ProcessingInstruction.cpp	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/dom/ProcessingInstruction.cpp	2012-08-26 23:48:39 UTC (rev 126717)
@@ -254,7 +254,7 @@
     m_loading = false;
 
     if (m_isCSS)
-        static_cast<CSSStyleSheet*>(m_sheet.get())->contents()->checkLoaded();
+        static_cast<CSSStyleSheet*>(m_sheet.get())->contents()->checkLoadCompleted();
 #if ENABLE(XSLT)
     else if (m_isXSL)
         static_cast<XSLStyleSheet*>(m_sheet.get())->checkLoaded();

Modified: trunk/Source/WebCore/dom/StyleElement.cpp (126716 => 126717)


--- trunk/Source/WebCore/dom/StyleElement.cpp	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/dom/StyleElement.cpp	2012-08-26 23:48:39 UTC (rev 126717)
@@ -181,7 +181,7 @@
     }
 
     if (m_sheet)
-        m_sheet->contents()->checkLoaded();
+        m_sheet->contents()->checkLoadCompleted();
 }
 
 bool StyleElement::isLoading() const

Modified: trunk/Source/WebCore/html/HTMLLinkElement.cpp (126716 => 126717)


--- trunk/Source/WebCore/html/HTMLLinkElement.cpp	2012-08-26 22:38:31 UTC (rev 126716)
+++ trunk/Source/WebCore/html/HTMLLinkElement.cpp	2012-08-26 23:48:39 UTC (rev 126717)
@@ -323,11 +323,10 @@
     m_sheet->setMediaQueries(MediaQuerySet::createAllowingDescriptionSyntax(m_media));
     m_sheet->setTitle(title());
 
-    styleSheet->parseAuthorStyleSheet(cachedStyleSheet, document()->securityOrigin());
+    styleSheet->parseAuthorStyleSheet(cachedStyleSheet, m_sheet.get());
 
     m_loading = false;
-    styleSheet->notifyLoadedSheet(cachedStyleSheet);
-    styleSheet->checkLoaded();
+    styleSheet->checkLoadCompleted();
 
 #if ENABLE(PARSED_STYLE_SHEET_CACHING)
     if (styleSheet->isCacheable())
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to