Title: [124720] trunk/Source/WebCore
Revision
124720
Author
[email protected]
Date
2012-08-05 14:03:42 -0700 (Sun, 05 Aug 2012)

Log Message

Don't reuse cached stylesheet with failed or canceled resource loads
https://bugs.webkit.org/show_bug.cgi?id=93203

Reviewed by Simon Fraser.

1) Go to apple.com
2) Reload repeatedly

Eventually you can get into state where some images don't load.
        
The problem is that a cached stylesheet may end up pointing to image resources that have been canceled (by the reload).
If this happens they stay in the canceled state even when the stylesheet is applied to a new document.
        
Fix by checking if all loads are complete (or pending) when restoring a cached stylesheet. The sheet is only used
if there are no failed or canceled loads. There are potential more sophisticated fixes but this is simple and safe.
Walking the sheet is fast and since it is only done on cache restore the cost is minimal.

No regression test yet though the new code does get exercised by the existing tests.

* css/CSSCrossfadeValue.cpp:
(WebCore::CSSCrossfadeValue::hasFailedOrCanceledSubresources):
(WebCore):
* css/CSSCrossfadeValue.h:
(CSSCrossfadeValue):
* css/CSSFontFaceSrcValue.cpp:
(WebCore::CSSFontFaceSrcValue::hasFailedOrCanceledSubresources):
(WebCore):
* css/CSSFontFaceSrcValue.h:
(CSSFontFaceSrcValue):
* css/CSSImageSetValue.cpp:
(WebCore::CSSImageSetValue::hasFailedOrCanceledSubresources):
(WebCore):
* css/CSSImageSetValue.h:
(CSSImageSetValue):
* css/CSSImageValue.cpp:
(WebCore::CSSImageValue::hasFailedOrCanceledSubresources):
(WebCore):
* css/CSSImageValue.h:
(CSSImageValue):
* css/CSSValue.cpp:
(WebCore::CSSValue::hasFailedOrCanceledSubresources):
(WebCore):
* css/CSSValue.h:
(CSSValue):
* css/CSSValueList.cpp:
(WebCore::CSSValueList::hasFailedOrCanceledSubresources):
(WebCore):
* css/CSSValueList.h:
(CSSValueList):
* css/StylePropertySet.cpp:
(WebCore::StylePropertySet::hasFailedOrCanceledSubresources):
(WebCore):
* css/StylePropertySet.h:
(StylePropertySet):
* css/StyleSheetContents.cpp:
(WebCore::childRulesHaveFailedOrCanceledSubresources):
(WebCore):
(WebCore::StyleSheetContents::hasFailedOrCanceledSubresources):
* css/StyleSheetContents.h:
(StyleSheetContents):
* loader/cache/CachedCSSStyleSheet.cpp:
(WebCore::CachedCSSStyleSheet::restoreParsedStyleSheet):
* loader/cache/CachedResource.h:
(WebCore::CachedResource::loadFailedOrCanceled):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (124719 => 124720)


--- trunk/Source/WebCore/ChangeLog	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/ChangeLog	2012-08-05 21:03:42 UTC (rev 124720)
@@ -1,3 +1,70 @@
+2012-08-05  Antti Koivisto  <[email protected]>
+
+        Don't reuse cached stylesheet with failed or canceled resource loads
+        https://bugs.webkit.org/show_bug.cgi?id=93203
+
+        Reviewed by Simon Fraser.
+
+        1) Go to apple.com
+        2) Reload repeatedly
+
+        Eventually you can get into state where some images don't load.
+        
+        The problem is that a cached stylesheet may end up pointing to image resources that have been canceled (by the reload).
+        If this happens they stay in the canceled state even when the stylesheet is applied to a new document.
+        
+        Fix by checking if all loads are complete (or pending) when restoring a cached stylesheet. The sheet is only used
+        if there are no failed or canceled loads. There are potential more sophisticated fixes but this is simple and safe.
+        Walking the sheet is fast and since it is only done on cache restore the cost is minimal.
+
+        No regression test yet though the new code does get exercised by the existing tests.
+
+        * css/CSSCrossfadeValue.cpp:
+        (WebCore::CSSCrossfadeValue::hasFailedOrCanceledSubresources):
+        (WebCore):
+        * css/CSSCrossfadeValue.h:
+        (CSSCrossfadeValue):
+        * css/CSSFontFaceSrcValue.cpp:
+        (WebCore::CSSFontFaceSrcValue::hasFailedOrCanceledSubresources):
+        (WebCore):
+        * css/CSSFontFaceSrcValue.h:
+        (CSSFontFaceSrcValue):
+        * css/CSSImageSetValue.cpp:
+        (WebCore::CSSImageSetValue::hasFailedOrCanceledSubresources):
+        (WebCore):
+        * css/CSSImageSetValue.h:
+        (CSSImageSetValue):
+        * css/CSSImageValue.cpp:
+        (WebCore::CSSImageValue::hasFailedOrCanceledSubresources):
+        (WebCore):
+        * css/CSSImageValue.h:
+        (CSSImageValue):
+        * css/CSSValue.cpp:
+        (WebCore::CSSValue::hasFailedOrCanceledSubresources):
+        (WebCore):
+        * css/CSSValue.h:
+        (CSSValue):
+        * css/CSSValueList.cpp:
+        (WebCore::CSSValueList::hasFailedOrCanceledSubresources):
+        (WebCore):
+        * css/CSSValueList.h:
+        (CSSValueList):
+        * css/StylePropertySet.cpp:
+        (WebCore::StylePropertySet::hasFailedOrCanceledSubresources):
+        (WebCore):
+        * css/StylePropertySet.h:
+        (StylePropertySet):
+        * css/StyleSheetContents.cpp:
+        (WebCore::childRulesHaveFailedOrCanceledSubresources):
+        (WebCore):
+        (WebCore::StyleSheetContents::hasFailedOrCanceledSubresources):
+        * css/StyleSheetContents.h:
+        (StyleSheetContents):
+        * loader/cache/CachedCSSStyleSheet.cpp:
+        (WebCore::CachedCSSStyleSheet::restoreParsedStyleSheet):
+        * loader/cache/CachedResource.h:
+        (WebCore::CachedResource::loadFailedOrCanceled):
+
 2012-08-05  Kentaro Hara  <[email protected]>
 
         [V8] Move V8Proxy methods that set DOM attributes/callbacks to V8Binding

Modified: trunk/Source/WebCore/css/CSSCrossfadeValue.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/CSSCrossfadeValue.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSCrossfadeValue.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -172,4 +172,13 @@
         m_ownerValue->crossfadeChanged(*rect);
 }
 
+bool CSSCrossfadeValue::hasFailedOrCanceledSubresources() const
+{
+    if (m_cachedFromImage && m_cachedFromImage->loadFailedOrCanceled())
+        return true;
+    if (m_cachedToImage && m_cachedToImage->loadFailedOrCanceled())
+        return true;
+    return false;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/css/CSSCrossfadeValue.h (124719 => 124720)


--- trunk/Source/WebCore/css/CSSCrossfadeValue.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSCrossfadeValue.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -61,6 +61,8 @@
 
     void setPercentage(PassRefPtr<CSSPrimitiveValue> percentageValue) { m_percentageValue = percentageValue; }
 
+    bool hasFailedOrCanceledSubresources() const;
+
 private:
     CSSCrossfadeValue(PassRefPtr<CSSValue> fromValue, PassRefPtr<CSSValue> toValue)
         : CSSImageGeneratorValue(CrossfadeClass)

Modified: trunk/Source/WebCore/css/CSSFontFaceSrcValue.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/CSSFontFaceSrcValue.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSFontFaceSrcValue.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -79,6 +79,13 @@
         addSubresourceURL(urls, styleSheet->completeURL(m_resource));
 }
 
+bool CSSFontFaceSrcValue::hasFailedOrCanceledSubresources() const
+{
+    if (!m_cachedFont)
+        return false;
+    return m_cachedFont->loadFailedOrCanceled();
+}
+
 CachedFont* CSSFontFaceSrcValue::cachedFont(Document* document)
 {
     if (!m_cachedFont) {

Modified: trunk/Source/WebCore/css/CSSFontFaceSrcValue.h (124719 => 124720)


--- trunk/Source/WebCore/css/CSSFontFaceSrcValue.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSFontFaceSrcValue.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -67,6 +67,8 @@
 
     void addSubresourceStyleURLs(ListHashSet<KURL>&, const StyleSheetContents*) const;
 
+    bool hasFailedOrCanceledSubresources() const;
+
     CachedFont* cachedFont(Document*);
 
 private:

Modified: trunk/Source/WebCore/css/CSSImageSetValue.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/CSSImageSetValue.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSImageSetValue.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -139,6 +139,16 @@
     return "-webkit-image-set(" + CSSValueList::customCssText() + ")";
 }
 
+bool CSSImageSetValue::hasFailedOrCanceledSubresources() const
+{
+    if (!m_imageSet || !m_imageSet->isCachedImageSet())
+        return false;
+    CachedResource* cachedResource = static_cast<StyleCachedImageSet*>(m_imageSet.get())->cachedImage();
+    if (!cachedResource)
+        return true;
+    return cachedResource->loadFailedOrCanceled();
+}
+
 CSSImageSetValue::CSSImageSetValue(const CSSImageSetValue& cloneFrom)
     : CSSValueList(cloneFrom)
     , m_accessedBestFitImage(false)

Modified: trunk/Source/WebCore/css/CSSImageSetValue.h (124719 => 124720)


--- trunk/Source/WebCore/css/CSSImageSetValue.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSImageSetValue.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -60,6 +60,8 @@
         float scaleFactor;
     };
 
+    bool hasFailedOrCanceledSubresources() const;
+
     PassRefPtr<CSSImageSetValue> cloneForCSSOM() const;
 
 protected:

Modified: trunk/Source/WebCore/css/CSSImageValue.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/CSSImageValue.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSImageValue.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -102,6 +102,16 @@
     m_accessedImage = false;
 }
 
+bool CSSImageValue::hasFailedOrCanceledSubresources() const
+{
+    if (!m_image || !m_image->isCachedImage())
+        return false;
+    CachedResource* cachedResource = static_cast<StyleCachedImage*>(m_image.get())->cachedImage();
+    if (!cachedResource)
+        return true;
+    return cachedResource->loadFailedOrCanceled();
+}
+
 String CSSImageValue::customCssText() const
 {
     return "url(" + quoteCSSURLIfNeeded(m_url) + ")";

Modified: trunk/Source/WebCore/css/CSSImageValue.h (124719 => 124720)


--- trunk/Source/WebCore/css/CSSImageValue.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSImageValue.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -46,6 +46,8 @@
 
     PassRefPtr<CSSValue> cloneForCSSOM() const;
 
+    bool hasFailedOrCanceledSubresources() const;
+
 protected:
     CSSImageValue(ClassType, const String& url);
 

Modified: trunk/Source/WebCore/css/CSSValue.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/CSSValue.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSValue.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -121,6 +121,26 @@
         static_cast<const CSSReflectValue*>(this)->addSubresourceStyleURLs(urls, styleSheet);
 }
 
+bool CSSValue::hasFailedOrCanceledSubresources() const
+{
+    // This should get called for internal instances only.
+    ASSERT(!isCSSOMSafe());
+
+    if (isValueList())
+        return static_cast<const CSSValueList*>(this)->hasFailedOrCanceledSubresources();
+    if (classType() == FontFaceSrcClass)
+        return static_cast<const CSSFontFaceSrcValue*>(this)->hasFailedOrCanceledSubresources();
+    if (classType() == ImageClass)
+        return static_cast<const CSSImageValue*>(this)->hasFailedOrCanceledSubresources();
+    if (classType() == CrossfadeClass)
+        return static_cast<const CSSCrossfadeValue*>(this)->hasFailedOrCanceledSubresources();
+#if ENABLE(CSS_IMAGE_SET)
+    if (classType() == ImageSetClass)
+        return static_cast<const CSSImageSetValue*>(this)->hasFailedOrCanceledSubresources();
+#endif
+    return false;
+}
+
 String CSSValue::cssText() const
 {
     if (m_isTextClone) {

Modified: trunk/Source/WebCore/css/CSSValue.h (124719 => 124720)


--- trunk/Source/WebCore/css/CSSValue.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSValue.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -117,6 +117,8 @@
 
     void addSubresourceStyleURLs(ListHashSet<KURL>&, const StyleSheetContents*) const;
 
+    bool hasFailedOrCanceledSubresources() const;
+
 protected:
 
     static const size_t ClassTypeBits = 5;

Modified: trunk/Source/WebCore/css/CSSValueList.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/CSSValueList.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSValueList.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -173,6 +173,15 @@
         m_values[i]->addSubresourceStyleURLs(urls, styleSheet);
 }
 
+bool CSSValueList::hasFailedOrCanceledSubresources() const
+{
+    for (unsigned i = 0; i < m_values.size(); ++i) {
+        if (m_values[i]->hasFailedOrCanceledSubresources())
+            return true;
+    }
+    return false;
+}
+
 CSSValueList::CSSValueList(const CSSValueList& cloneFrom)
     : CSSValue(cloneFrom.classType(), /* isCSSOMSafe */ true)
 {

Modified: trunk/Source/WebCore/css/CSSValueList.h (124719 => 124720)


--- trunk/Source/WebCore/css/CSSValueList.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/CSSValueList.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -64,6 +64,8 @@
 #endif
 
     void addSubresourceStyleURLs(ListHashSet<KURL>&, const StyleSheetContents*) const;
+
+    bool hasFailedOrCanceledSubresources() const;
     
     PassRefPtr<CSSValueList> cloneForCSSOM() const;
 

Modified: trunk/Source/WebCore/css/StylePropertySet.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/StylePropertySet.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/StylePropertySet.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -894,6 +894,16 @@
         propertyAt(i).value()->addSubresourceStyleURLs(urls, contextStyleSheet);
 }
 
+bool StylePropertySet::hasFailedOrCanceledSubresources() const
+{
+    unsigned size = propertyCount();
+    for (unsigned i = 0; i < size; ++i) {
+        if (propertyAt(i).value()->hasFailedOrCanceledSubresources())
+            return true;
+    }
+    return false;
+}
+
 // This is the list of properties we want to copy in the copyBlockProperties() function.
 // It is the list of CSS properties that apply specially to block-level elements.
 static const CSSPropertyID blockProperties[] = {

Modified: trunk/Source/WebCore/css/StylePropertySet.h (124719 => 124720)


--- trunk/Source/WebCore/css/StylePropertySet.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/StylePropertySet.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -110,6 +110,8 @@
 
     bool isMutable() const { return m_isMutable; }
 
+    bool hasFailedOrCanceledSubresources() const;
+
     static unsigned averageSizeInBytes();
     void reportMemoryUsage(MemoryObjectInfo*) const;
 

Modified: trunk/Source/WebCore/css/StyleSheetContents.cpp (124719 => 124720)


--- trunk/Source/WebCore/css/StyleSheetContents.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/StyleSheetContents.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -410,6 +410,46 @@
     }
 }
 
+static bool childRulesHaveFailedOrCanceledSubresources(const Vector<RefPtr<StyleRuleBase> >& rules)
+{
+    for (unsigned i = 0; i < rules.size(); ++i) {
+        const StyleRuleBase* rule = rules[i].get();
+        switch (rule->type()) {
+        case StyleRuleBase::Style:
+            if (static_cast<const StyleRule*>(rule)->properties()->hasFailedOrCanceledSubresources())
+                return true;
+            break;
+        case StyleRuleBase::FontFace:
+            if (static_cast<const StyleRuleFontFace*>(rule)->properties()->hasFailedOrCanceledSubresources())
+                return true;
+            break;
+        case StyleRuleBase::Media:
+            if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleMedia*>(rule)->childRules()))
+                return true;
+            break;
+        case StyleRuleBase::Region:
+            if (childRulesHaveFailedOrCanceledSubresources(static_cast<const StyleRuleRegion*>(rule)->childRules()))
+                return true;
+            break;
+        case StyleRuleBase::Import:
+            ASSERT_NOT_REACHED();
+        case StyleRuleBase::Page:
+        case StyleRuleBase::Keyframes:
+        case StyleRuleBase::Unknown:
+        case StyleRuleBase::Charset:
+        case StyleRuleBase::Keyframe:
+            break;
+        }
+    }
+    return false;
+}
+
+bool StyleSheetContents::hasFailedOrCanceledSubresources() const
+{
+    ASSERT(isCacheable());
+    return childRulesHaveFailedOrCanceledSubresources(m_childRules);
+}
+
 StyleSheetContents* StyleSheetContents::parentStyleSheet() const
 {
     return m_ownerRule ? m_ownerRule->parentStyleSheet() : 0;

Modified: trunk/Source/WebCore/css/StyleSheetContents.h (124719 => 124720)


--- trunk/Source/WebCore/css/StyleSheetContents.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/css/StyleSheetContents.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -79,6 +79,7 @@
     const String& charset() const { return m_parserContext.charset; }
 
     bool loadCompleted() const { return m_loadCompleted; }
+    bool hasFailedOrCanceledSubresources() const;
 
     KURL completeURL(const String& url) const;
     void addSubresourceStyleURLs(ListHashSet<KURL>&);

Modified: trunk/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp (124719 => 124720)


--- trunk/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/loader/cache/CachedCSSStyleSheet.cpp	2012-08-05 21:03:42 UTC (rev 124720)
@@ -168,6 +168,12 @@
 {
     if (!m_parsedStyleSheetCache)
         return 0;
+    if (m_parsedStyleSheetCache->hasFailedOrCanceledSubresources()) {
+        m_parsedStyleSheetCache->removedFromMemoryCache();
+        m_parsedStyleSheetCache.clear();
+        return 0;
+    }
+
     ASSERT(m_parsedStyleSheetCache->isCacheable());
     ASSERT(m_parsedStyleSheetCache->isInMemoryCache());
 

Modified: trunk/Source/WebCore/loader/cache/CachedResource.h (124719 => 124720)


--- trunk/Source/WebCore/loader/cache/CachedResource.h	2012-08-05 20:55:48 UTC (rev 124719)
+++ trunk/Source/WebCore/loader/cache/CachedResource.h	2012-08-05 21:03:42 UTC (rev 124720)
@@ -205,6 +205,7 @@
 
     bool wasCanceled() const { return m_status == Canceled; }
     bool errorOccurred() const { return (m_status == LoadError || m_status == DecodeError); }
+    bool loadFailedOrCanceled() { return m_status == Canceled || m_status == LoadError; }
 
     bool sendResourceLoadCallbacks() const { return m_options.sendLoadCallbacks == SendCallbacks; }
     
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to