Implement CSS3 Images cross-fade() image function
https://bugs.webkit.org/show_bug.cgi?id=52162
<rdar://problem/10209254>

Reviewed by Simon Fraser.

Render -webkit-cross-fade. Only cross-fades entirely composed of images will render for now,
cross-fades involving generated images are not yet implemented.

Reorganize GeneratedImage to be the base class for GeneratorGeneratedImage and CrossfadeGeneratedImage.

Add a pending state to CSSImageGeneratorValue, which is used to enable the pending-images loading
mechanism for -webkit-cross-fade's sub-images. Rework the logic in CSSStyleSelector to support pending
generated images.

Support parsing fractional values for the cross-fade amount (for example, 0.5 = 50%). Clamp cross-fade
amount to 0-1 range.

Tests: css3/images/cross-fade-invalidation.html
       css3/images/cross-fade-simple.html
       css3/images/cross-fade-sizing.html
       css3/images/cross-fade-tiled.html

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.xcodeproj/project.pbxproj:
* css/CSSCanvasValue.h:
(WebCore::CSSCanvasValue::isPending):
(WebCore::CSSCanvasValue::loadSubimages):
* css/CSSCrossfadeValue.cpp:
(WebCore::CSSCrossfadeValue::isPending):
(WebCore::CSSCrossfadeValue::loadSubimages):
(WebCore::subimageIsPending):
(WebCore::loadSubimage):
(WebCore::cachedImageForCSSValue):
(WebCore::CSSCrossfadeValue::image):
(WebCore::CSSCrossfadeValue::crossfadeChanged):
* css/CSSCrossfadeValue.h:
(WebCore::CSSCrossfadeValue::create):
(WebCore::CSSCrossfadeValue::~CSSCrossfadeValue):
(WebCore::CSSCrossfadeValue::fixedSize):
(WebCore::CSSCrossfadeValue::CSSCrossfadeValue):
(WebCore::CSSCrossfadeValue::CrossfadeObserverProxy::CrossfadeObserverProxy):
* css/CSSGradientValue.cpp:
(WebCore::CSSGradientValue::image):
* css/CSSGradientValue.h:
(WebCore::CSSGradientValue::isPending):
(WebCore::CSSGradientValue::loadSubimages):
* css/CSSImageGeneratorValue.cpp:
(WebCore::CSSImageGeneratorValue::generatedOrPendingImage):
(WebCore::CSSImageGeneratorValue::generatedImage):
(WebCore::CSSImageGeneratorValue::isPending):
(WebCore::CSSImageGeneratorValue::loadSubimages):
* css/CSSImageGeneratorValue.h:
* css/CSSParser.cpp:
(WebCore::CSSParser::parseCrossfade):
* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::styleImage):
(WebCore::CSSStyleSelector::generatedOrPendingFromValue):
(WebCore::CSSStyleSelector::loadPendingImage):
(WebCore::CSSStyleSelector::loadPendingImages):
* css/CSSStyleSelector.h:
* platform/graphics/BitmapImage.h:
* platform/graphics/CrossfadeGeneratedImage.cpp: Added.
(WebCore::CrossfadeGeneratedImage::CrossfadeGeneratedImage):
(WebCore::CrossfadeGeneratedImage::~CrossfadeGeneratedImage):
(WebCore::CrossfadeGeneratedImage::drawCrossfade):
(WebCore::CrossfadeGeneratedImage::draw):
(WebCore::CrossfadeGeneratedImage::drawPattern):
(WebCore::CrossfadeGeneratedImage::imageChanged):
* platform/graphics/CrossfadeGeneratedImage.h: Added.
(WebCore::CrossfadeGeneratedImage::create):
(WebCore::CrossfadeSubimageObserverProxy::CrossfadeSubimageObserverProxy):
(WebCore::CrossfadeSubimageObserverProxy::setReady):
* platform/graphics/GeneratedImage.h:
(WebCore::GeneratedImage::GeneratedImage):
* platform/graphics/GeneratorGeneratedImage.cpp: Renamed from Source/WebCore/platform/graphics/GeneratedImage.cpp.
(WebCore::GeneratorGeneratedImage::draw):
(WebCore::GeneratorGeneratedImage::drawPattern):
(WebCore::GeneratedImage::computeIntrinsicDimensions):
* platform/graphics/GeneratorGeneratedImage.h: Copied from Source/WebCore/platform/graphics/GeneratedImage.h.
(WebCore::GeneratorGeneratedImage::create):
(WebCore::GeneratorGeneratedImage::~GeneratorGeneratedImage):
(WebCore::GeneratorGeneratedImage::GeneratorGeneratedImage):
* platform/graphics/Image.h:
* platform/graphics/ImageBuffer.h:
* rendering/style/StylePendingImage.h:
(WebCore::StylePendingImage::create):
(WebCore::StylePendingImage::data):
(WebCore::StylePendingImage::cssImageValue):
(WebCore::StylePendingImage::cssImageGeneratorValue):
(WebCore::StylePendingImage::StylePendingImage):

Add tests of -webkit-cross-fade, ensuring that simple cross-fades between
two images work correctly.

Adjust fast/css/getComputedStyle/computed-style-cross-fade.html to test
fractional and out-of-range cross-fade percentage values.

* css3/images/cross-fade-invalidation.html: Added.
* css3/images/cross-fade-simple.html: Added.
* css3/images/cross-fade-sizing.html: Added.
* css3/images/cross-fade-tiled.html: Added.
* css3/images/resources/blue-10.png: Added.
* css3/images/resources/blue-100.png: Added.
* css3/images/resources/green-10.png: Added.
* css3/images/resources/green-100.png: Added.
* css3/images/resources/green-circle.svg: Added.
* css3/images/resources/red-10.png: Added.
* css3/images/resources/red-100.png: Added.
* fast/css/getComputedStyle/computed-style-cross-fade-expected.txt:
* fast/css/getComputedStyle/computed-style-cross-fade.html:
* platform/mac/css3/images/cross-fade-invalidation-expected.png: Added.
* platform/mac/css3/images/cross-fade-invalidation-expected.txt: Added.
* platform/mac/css3/images/cross-fade-simple-expected.png: Added.
* platform/mac/css3/images/cross-fade-simple-expected.txt: Added.
* platform/mac/css3/images/cross-fade-sizing-expected.png: Added.
* platform/mac/css3/images/cross-fade-sizing-expected.txt: Added.
* platform/mac/css3/images/cross-fade-tiled-expected.png: Added.
* platform/mac/css3/images/cross-fade-tiled-expected.txt: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@100535 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/css/CSSCanvasValue.h b/Source/WebCore/css/CSSCanvasValue.h
index 232a525..efad7e6 100644
--- a/Source/WebCore/css/CSSCanvasValue.h
+++ b/Source/WebCore/css/CSSCanvasValue.h
@@ -44,6 +44,9 @@
     bool isFixedSize() const { return true; }
     IntSize fixedSize(const RenderObject*);
 
+    bool isPending() const { return false; }
+    void loadSubimages(CachedResourceLoader*) { }
+
     void setName(const String& name) { m_name = name; }
 
 private:
diff --git a/Source/WebCore/css/CSSCrossfadeValue.cpp b/Source/WebCore/css/CSSCrossfadeValue.cpp
index b77069f..acbca87 100644
--- a/Source/WebCore/css/CSSCrossfadeValue.cpp
+++ b/Source/WebCore/css/CSSCrossfadeValue.cpp
@@ -26,8 +26,62 @@
 #include "config.h"
 #include "CSSCrossfadeValue.h"
 
+#include "CSSImageValue.h"
+#include "CachedImage.h"
+#include "CachedResourceLoader.h"
+#include "CrossfadeGeneratedImage.h"
+#include "ImageBuffer.h"
+#include "RenderObject.h"
+#include "StyleCachedImage.h"
+#include "StyleGeneratedImage.h"
+
 namespace WebCore {
 
+static bool subimageIsPending(CSSValue* value)
+{
+    if (value->isImageValue())
+        return static_cast<CSSImageValue*>(value)->cachedOrPendingImage()->isPendingImage();
+    
+    if (value->isImageGeneratorValue())
+        return static_cast<CSSImageGeneratorValue*>(value)->isPending();
+    
+    ASSERT_NOT_REACHED();
+    
+    return false;
+}
+
+static void loadSubimage(CSSValue* value, CachedResourceLoader* cachedResourceLoader)
+{
+    if (value->isImageValue()) {
+        static_cast<CSSImageValue*>(value)->cachedImage(cachedResourceLoader);
+        return;
+    }
+    
+    if (value->isImageGeneratorValue()) {
+        static_cast<CSSImageGeneratorValue*>(value)->loadSubimages(cachedResourceLoader);
+        return;
+    }
+    
+    ASSERT_NOT_REACHED();
+}
+
+static CachedImage* cachedImageForCSSValue(CSSValue* value, const RenderObject* renderer)
+{
+    CachedResourceLoader* cachedResourceLoader = renderer->document()->cachedResourceLoader();
+    
+    if (value->isImageValue())
+        return static_cast<CSSImageValue*>(value)->cachedImage(cachedResourceLoader)->cachedImage();
+    
+    if (value->isImageGeneratorValue()) {
+        // FIXME: Handle CSSImageGeneratorValue (and thus cross-fades with gradients and canvas).
+        return 0;
+    }
+    
+    ASSERT_NOT_REACHED();
+    
+    return 0;
+}
+
 String CSSCrossfadeValue::customCssText() const
 {
     String result = "-webkit-cross-fade(";
@@ -40,17 +94,58 @@
 
 IntSize CSSCrossfadeValue::fixedSize(const RenderObject* renderer)
 {
-    UNUSED_PARAM(renderer);
+    float percentage = m_percentage->getFloatValue();
+    float inversePercentage = 1 - percentage;
 
-    return IntSize();
+    CachedImage* fromImage = cachedImageForCSSValue(m_fromImage.get(), renderer);
+    CachedImage* toImage = cachedImageForCSSValue(m_toImage.get(), renderer);
+
+    if (!fromImage || !toImage)
+        return IntSize();
+
+    IntSize fromImageSize = fromImage->image()->size();
+    IntSize toImageSize = toImage->image()->size();
+
+    return IntSize(fromImageSize.width() * inversePercentage + toImageSize.width() * percentage,
+        fromImageSize.height() * inversePercentage + toImageSize.height() * percentage);
+}
+
+bool CSSCrossfadeValue::isPending() const
+{
+    return subimageIsPending(m_fromImage.get()) || subimageIsPending(m_toImage.get());
+}
+
+void CSSCrossfadeValue::loadSubimages(CachedResourceLoader* cachedResourceLoader)
+{
+    loadSubimage(m_fromImage.get(), cachedResourceLoader);
+    loadSubimage(m_toImage.get(), cachedResourceLoader);
 }
 
 PassRefPtr<Image> CSSCrossfadeValue::image(RenderObject* renderer, const IntSize& size)
 {
-    UNUSED_PARAM(renderer);
-    UNUSED_PARAM(size);
+    if (size.isEmpty())
+        return 0;
 
-    return 0;
+    CachedImage* fromImage = cachedImageForCSSValue(m_fromImage.get(), renderer);
+    CachedImage* toImage = cachedImageForCSSValue(m_toImage.get(), renderer);
+
+    if (!fromImage || !toImage)
+        return Image::nullImage();
+
+    m_generatedImage = CrossfadeGeneratedImage::create(fromImage, toImage, m_percentage->getFloatValue(), &m_crossfadeObserver, fixedSize(renderer), size);
+
+    return m_generatedImage.get();
+}
+
+void CSSCrossfadeValue::crossfadeChanged(const IntRect& rect)
+{
+    UNUSED_PARAM(rect);
+
+    RenderObjectSizeCountMap::const_iterator end = clients().end();
+    for (RenderObjectSizeCountMap::const_iterator curr = clients().begin(); curr != end; ++curr) {
+        RenderObject* client = const_cast<RenderObject*>(curr->first);
+        client->imageChanged(static_cast<WrappedImagePtr>(this));
+    }
 }
 
 } // namespace WebCore
diff --git a/Source/WebCore/css/CSSCrossfadeValue.h b/Source/WebCore/css/CSSCrossfadeValue.h
index d549fbe..233a80a 100644
--- a/Source/WebCore/css/CSSCrossfadeValue.h
+++ b/Source/WebCore/css/CSSCrossfadeValue.h
@@ -27,37 +27,63 @@
 #define CSSCrossfadeValue_h
 
 #include "CSSImageGeneratorValue.h"
-#include "CSSImageValue.h"
+#include "CSSPrimitiveValue.h"
 #include "Image.h"
 #include "ImageObserver.h"
 
 namespace WebCore {
 
+class CachedImage;
 class RenderObject;
+class Document;
 
 class CSSCrossfadeValue : public CSSImageGeneratorValue {
 public:
-    static PassRefPtr<CSSCrossfadeValue> create(PassRefPtr<CSSImageValue> fromImage, PassRefPtr<CSSImageValue> toImage) { return adoptRef(new CSSCrossfadeValue(fromImage, toImage)); }
+    static PassRefPtr<CSSCrossfadeValue> create(PassRefPtr<CSSValue> fromImage, PassRefPtr<CSSValue> toImage)
+    {
+        return adoptRef(new CSSCrossfadeValue(fromImage, toImage));
+    }
 
     String customCssText() const;
 
     PassRefPtr<Image> image(RenderObject*, const IntSize&);
-    bool isFixedSize() const { return false; }
+    bool isFixedSize() const { return true; }
     IntSize fixedSize(const RenderObject*);
 
+    bool isPending() const;
+    void loadSubimages(CachedResourceLoader*);
+
     void setPercentage(PassRefPtr<CSSPrimitiveValue> percentage) { m_percentage = percentage; }
 
 private:
-    CSSCrossfadeValue(PassRefPtr<CSSImageValue> fromImage, PassRefPtr<CSSImageValue> toImage)
+    CSSCrossfadeValue(PassRefPtr<CSSValue> fromImage, PassRefPtr<CSSValue> toImage)
         : CSSImageGeneratorValue(CrossfadeClass)
         , m_fromImage(fromImage)
         , m_toImage(toImage)
-    {
-    }
+        , m_crossfadeObserver(this) { }
 
-    RefPtr<CSSImageValue> m_fromImage;
-    RefPtr<CSSImageValue> m_toImage;
+    class CrossfadeObserverProxy : public ImageObserver {
+    public:
+        CrossfadeObserverProxy(CSSCrossfadeValue* ownerValue) : m_ownerValue(ownerValue) { }
+        virtual ~CrossfadeObserverProxy() { }
+        virtual void changedInRect(const Image*, const IntRect& rect) OVERRIDE { m_ownerValue->crossfadeChanged(rect); };
+        virtual bool shouldPauseAnimation(const Image*) OVERRIDE { return false; }
+        virtual void didDraw(const Image*) OVERRIDE { }
+        virtual void animationAdvanced(const Image*) OVERRIDE { }
+        virtual void decodedSizeChanged(const Image*, int) OVERRIDE { }
+    private:
+        CSSCrossfadeValue* m_ownerValue;
+    };
+
+    void crossfadeChanged(const IntRect&);
+
+    RefPtr<CSSValue> m_fromImage;
+    RefPtr<CSSValue> m_toImage;
     RefPtr<CSSPrimitiveValue> m_percentage;
+
+    RefPtr<Image> m_generatedImage;
+
+    CrossfadeObserverProxy m_crossfadeObserver;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/css/CSSGradientValue.cpp b/Source/WebCore/css/CSSGradientValue.cpp
index feb01f4..b55b475 100644
--- a/Source/WebCore/css/CSSGradientValue.cpp
+++ b/Source/WebCore/css/CSSGradientValue.cpp
@@ -26,9 +26,9 @@
 #include "config.h"
 #include "CSSGradientValue.h"
 
-#include "CSSValueKeywords.h"
 #include "CSSStyleSelector.h"
-#include "GeneratedImage.h"
+#include "CSSValueKeywords.h"
+#include "GeneratorGeneratedImage.h"
 #include "Gradient.h"
 #include "Image.h"
 #include "IntSize.h"
@@ -67,7 +67,7 @@
         gradient = static_cast<CSSRadialGradientValue*>(this)->createGradient(renderer, size);
     }
 
-    RefPtr<Image> newImage = GeneratedImage::create(gradient, size);
+    RefPtr<Image> newImage = GeneratorGeneratedImage::create(gradient, size);
     if (cacheable)
         putImage(size, newImage);
 
diff --git a/Source/WebCore/css/CSSGradientValue.h b/Source/WebCore/css/CSSGradientValue.h
index f13ac98..ea10eb8 100644
--- a/Source/WebCore/css/CSSGradientValue.h
+++ b/Source/WebCore/css/CSSGradientValue.h
@@ -69,6 +69,9 @@
     bool isFixedSize() const { return false; }
     IntSize fixedSize(const RenderObject*) const { return IntSize(); }
 
+    bool isPending() const { return false; }
+    void loadSubimages(CachedResourceLoader*) { }
+
 protected:
     CSSGradientValue(ClassType classType, CSSGradientRepeat repeat, bool deprecatedType = false)
         : CSSImageGeneratorValue(classType)
diff --git a/Source/WebCore/css/CSSImageGeneratorValue.cpp b/Source/WebCore/css/CSSImageGeneratorValue.cpp
index 1c3c652..41b464c 100644
--- a/Source/WebCore/css/CSSImageGeneratorValue.cpp
+++ b/Source/WebCore/css/CSSImageGeneratorValue.cpp
@@ -32,6 +32,7 @@
 #include "Image.h"
 #include "RenderObject.h"
 #include "StyleGeneratedImage.h"
+#include "StylePendingImage.h"
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
@@ -110,13 +111,26 @@
     m_images.add(size, image);
 }
 
+StyleImage* CSSImageGeneratorValue::generatedOrPendingImage()
+{
+    if (isPending())
+        m_image = StylePendingImage::create(this).get();
+    else if (!m_accessedImage) {
+        m_accessedImage = true;
+        m_image = StyleGeneratedImage::create(this, isFixedSize());
+    }
+
+    return m_image.get();
+}
+
 StyleGeneratedImage* CSSImageGeneratorValue::generatedImage()
 {
     if (!m_accessedImage) {
         m_accessedImage = true;
         m_image = StyleGeneratedImage::create(this, isFixedSize());
     }
-    return m_image.get();
+
+    return static_cast<StyleGeneratedImage*>(m_image.get());
 }
 
 PassRefPtr<Image> CSSImageGeneratorValue::image(RenderObject* renderer, const IntSize& size)
@@ -170,4 +184,41 @@
     return IntSize();
 }
 
+bool CSSImageGeneratorValue::isPending() const
+{
+    switch (classType()) {
+    case CrossfadeClass:
+        return static_cast<const CSSCrossfadeValue*>(this)->isPending();
+    case CanvasClass:
+        return static_cast<const CSSCanvasValue*>(this)->isPending();
+    case LinearGradientClass:
+        return static_cast<const CSSLinearGradientValue*>(this)->isPending();
+    case RadialGradientClass:
+        return static_cast<const CSSRadialGradientValue*>(this)->isPending();
+    default:
+        ASSERT_NOT_REACHED();
+    }
+    return false;
+}
+
+void CSSImageGeneratorValue::loadSubimages(CachedResourceLoader* cachedResourceLoader)
+{
+    switch (classType()) {
+    case CrossfadeClass:
+        static_cast<CSSCrossfadeValue*>(this)->loadSubimages(cachedResourceLoader);
+        break;
+    case CanvasClass:
+        static_cast<CSSCanvasValue*>(this)->loadSubimages(cachedResourceLoader);
+        break;
+    case LinearGradientClass:
+        static_cast<CSSLinearGradientValue*>(this)->loadSubimages(cachedResourceLoader);
+        break;
+    case RadialGradientClass:
+        static_cast<CSSRadialGradientValue*>(this)->loadSubimages(cachedResourceLoader);
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+
 } // namespace WebCore
diff --git a/Source/WebCore/css/CSSImageGeneratorValue.h b/Source/WebCore/css/CSSImageGeneratorValue.h
index d0eb65b..1ab4474 100644
--- a/Source/WebCore/css/CSSImageGeneratorValue.h
+++ b/Source/WebCore/css/CSSImageGeneratorValue.h
@@ -33,9 +33,11 @@
 
 namespace WebCore {
 
+class CachedResourceLoader;
 class Image;
 class RenderObject;
 class StyleGeneratedImage;
+class StyleImage;
 
 struct SizeAndCount {
     SizeAndCount(IntSize newSize = IntSize(), int newCount = 0)
@@ -58,11 +60,16 @@
     void removeClient(RenderObject*);
     PassRefPtr<Image> image(RenderObject*, const IntSize&);
 
+    StyleImage* generatedOrPendingImage();
     StyleGeneratedImage* generatedImage();
 
     bool isFixedSize() const;
     IntSize fixedSize(const RenderObject*);
 
+    bool isPending() const;
+
+    void loadSubimages(CachedResourceLoader*);
+
 protected:
     CSSImageGeneratorValue(ClassType);
 
@@ -70,7 +77,7 @@
     void putImage(const IntSize&, PassRefPtr<Image>);
     const RenderObjectSizeCountMap& clients() const { return m_clients; }
 
-    RefPtr<StyleGeneratedImage> m_image;
+    RefPtr<StyleImage> m_image;
     bool m_accessedImage;
 
     HashCountedSet<IntSize> m_sizes; // A count of how many times a given image size is in use.
diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp
index 93a0ad8..b6b0b28 100644
--- a/Source/WebCore/css/CSSParser.cpp
+++ b/Source/WebCore/css/CSSParser.cpp
@@ -6313,12 +6313,20 @@
         return false;
     a = args->next();
 
-    // The third argument is the crossfade value. It is a percentage.
-    if (!a || a->unit != CSSPrimitiveValue::CSS_PERCENTAGE)
+    // The third argument is the crossfade value. It is a percentage or a fractional number.
+    RefPtr<CSSPrimitiveValue> percentage;
+    if (!a)
+        return false;
+    
+    if (a->unit == CSSPrimitiveValue::CSS_PERCENTAGE)
+        percentage = primitiveValueCache()->createValue(clampTo<double>(a->fValue / 100, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
+    else if (a->unit == CSSPrimitiveValue::CSS_NUMBER)
+        percentage = primitiveValueCache()->createValue(clampTo<double>(a->fValue, 0, 1), CSSPrimitiveValue::CSS_NUMBER);
+    else
         return false;
 
-    result = CSSCrossfadeValue::create(static_cast<CSSImageValue*>(fromImageValue.get()), static_cast<CSSImageValue*>(toImageValue.get()));
-    result->setPercentage(createPrimitiveNumericValue(a));
+    result = CSSCrossfadeValue::create(fromImageValue, toImageValue);
+    result->setPercentage(percentage);
 
     crossfade = result;
 
diff --git a/Source/WebCore/css/CSSStyleSelector.cpp b/Source/WebCore/css/CSSStyleSelector.cpp
index 7527d73..4d459e0 100644
--- a/Source/WebCore/css/CSSStyleSelector.cpp
+++ b/Source/WebCore/css/CSSStyleSelector.cpp
@@ -4279,7 +4279,7 @@
         return cachedOrPendingFromValue(property, static_cast<CSSImageValue*>(value));
 
     if (value->isImageGeneratorValue())
-        return static_cast<CSSImageGeneratorValue*>(value)->generatedImage();
+        return generatedOrPendingFromValue(property, static_cast<CSSImageGeneratorValue*>(value));
 
     return 0;
 }
@@ -4292,6 +4292,14 @@
     return image;
 }
 
+StyleImage* CSSStyleSelector::generatedOrPendingFromValue(CSSPropertyID property, CSSImageGeneratorValue* value)
+{
+    StyleImage* image = value->generatedOrPendingImage();
+    if (image && image->isPendingImage())
+        m_pendingImageProperties.add(property);
+    return image;
+}
+
 void CSSStyleSelector::mapFillImage(CSSPropertyID property, FillLayer* layer, CSSValue* value)
 {
     if (value->isInitialValue()) {
@@ -5667,6 +5675,24 @@
 
 #endif
 
+StyleImage* CSSStyleSelector::loadPendingImage(StylePendingImage* pendingImage)
+{
+    CachedResourceLoader* cachedResourceLoader = m_element->document()->cachedResourceLoader();
+
+    if (pendingImage->cssImageValue()) {
+        CSSImageValue* imageValue = pendingImage->cssImageValue();
+        return imageValue->cachedImage(cachedResourceLoader);
+    }
+
+    if (pendingImage->cssImageGeneratorValue()) {
+        CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue();
+        imageGeneratorValue->loadSubimages(cachedResourceLoader);
+        return imageGeneratorValue->generatedImage();
+    }
+
+    return 0;
+}
+
 void CSSStyleSelector::loadPendingImages()
 {
     if (m_pendingImageProperties.isEmpty())
@@ -5676,14 +5702,12 @@
     for (HashSet<int>::const_iterator it = m_pendingImageProperties.begin(); it != end; ++it) {
         CSSPropertyID currentProperty = static_cast<CSSPropertyID>(*it);
 
-        CachedResourceLoader* cachedResourceLoader = m_element->document()->cachedResourceLoader();
-
         switch (currentProperty) {
             case CSSPropertyBackgroundImage: {
                 for (FillLayer* backgroundLayer = m_style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) {
                     if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) {
-                        CSSImageValue* imageValue = static_cast<StylePendingImage*>(backgroundLayer->image())->cssImageValue();
-                        backgroundLayer->setImage(imageValue->cachedImage(cachedResourceLoader));
+                        StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image()));
+                        backgroundLayer->setImage(loadedImage);
                     }
                 }
                 break;
@@ -5692,11 +5716,11 @@
             case CSSPropertyContent: {
                 for (ContentData* contentData = const_cast<ContentData*>(m_style->contentData()); contentData; contentData = contentData->next()) {
                     if (contentData->isImage()) {
-                        const StyleImage* image = static_cast<ImageContentData*>(contentData)->image();
+                        StyleImage* image = static_cast<ImageContentData*>(contentData)->image();
                         if (image->isPendingImage()) {
-                            CSSImageValue* imageValue = static_cast<const StylePendingImage*>(image)->cssImageValue();
-                            if (StyleCachedImage* cachedImage = imageValue->cachedImage(cachedResourceLoader))
-                                static_cast<ImageContentData*>(contentData)->setImage(cachedImage);
+                            StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image));
+                            if (loadedImage)
+                                static_cast<ImageContentData*>(contentData)->setImage(loadedImage);
                         }
                     }
                 }
@@ -5709,8 +5733,8 @@
                         CursorData& currentCursor = cursorList->at(i);
                         if (StyleImage* image = currentCursor.image()) {
                             if (image->isPendingImage()) {
-                                CSSImageValue* imageValue = static_cast<StylePendingImage*>(image)->cssImageValue();
-                                currentCursor.setImage(imageValue->cachedImage(cachedResourceLoader));
+                                StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image));
+                                currentCursor.setImage(loadedImage);
                             }
                         }
                     }
@@ -5720,16 +5744,16 @@
 
             case CSSPropertyListStyleImage: {
                 if (m_style->listStyleImage() && m_style->listStyleImage()->isPendingImage()) {
-                    CSSImageValue* imageValue = static_cast<StylePendingImage*>(m_style->listStyleImage())->cssImageValue();
-                    m_style->setListStyleImage(imageValue->cachedImage(cachedResourceLoader));
+                    StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(m_style->listStyleImage()));
+                    m_style->setListStyleImage(loadedImage);
                 }
                 break;
             }
 
             case CSSPropertyBorderImageSource: {
                 if (m_style->borderImageSource() && m_style->borderImageSource()->isPendingImage()) {
-                    CSSImageValue* imageValue = static_cast<StylePendingImage*>(m_style->borderImageSource())->cssImageValue();
-                    m_style->setBorderImageSource(imageValue->cachedImage(cachedResourceLoader));
+                    StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(m_style->borderImageSource()));
+                    m_style->setBorderImageSource(loadedImage);
                 }
                 break;
             }
@@ -5738,8 +5762,8 @@
                 if (StyleReflection* reflection = m_style->boxReflect()) {
                     const NinePieceImage& maskImage = reflection->mask();
                     if (maskImage.image() && maskImage.image()->isPendingImage()) {
-                        CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskImage.image())->cssImageValue();
-                        reflection->setMask(NinePieceImage(imageValue->cachedImage(cachedResourceLoader), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule()));
+                        StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image()));
+                        reflection->setMask(NinePieceImage(loadedImage, maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule()));
                     }
                 }
                 break;
@@ -5747,8 +5771,8 @@
 
             case CSSPropertyWebkitMaskBoxImageSource: {
                 if (m_style->maskBoxImageSource() && m_style->maskBoxImageSource()->isPendingImage()) {
-                    CSSImageValue* imageValue = static_cast<StylePendingImage*>(m_style->maskBoxImageSource())->cssImageValue();
-                    m_style->setMaskBoxImageSource(imageValue->cachedImage(cachedResourceLoader));
+                    StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(m_style->maskBoxImageSource()));
+                    m_style->setMaskBoxImageSource(loadedImage);
                 }
                 break;
             }
@@ -5756,8 +5780,8 @@
             case CSSPropertyWebkitMaskImage: {
                 for (FillLayer* maskLayer = m_style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
                     if (maskLayer->image() && maskLayer->image()->isPendingImage()) {
-                        CSSImageValue* imageValue = static_cast<StylePendingImage*>(maskLayer->image())->cssImageValue();
-                        maskLayer->setImage(imageValue->cachedImage(cachedResourceLoader));
+                        StyleImage* loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image()));
+                        maskLayer->setImage(loadedImage);
                     }
                 }
                 break;
diff --git a/Source/WebCore/css/CSSStyleSelector.h b/Source/WebCore/css/CSSStyleSelector.h
index 979fc99..b48939c 100644
--- a/Source/WebCore/css/CSSStyleSelector.h
+++ b/Source/WebCore/css/CSSStyleSelector.h
@@ -44,6 +44,7 @@
 class CSSProperty;
 class CSSFontFace;
 class CSSFontFaceRule;
+class CSSImageGeneratorValue;
 class CSSImageValue;
 class CSSRegionStyleRule;
 class CSSRuleList;
@@ -67,6 +68,7 @@
 class RuleSet;
 class Settings;
 class StyleImage;
+class StylePendingImage;
 class StyleShader;
 class StyleSheet;
 class StyleSheetList;
@@ -294,6 +296,7 @@
 
     StyleImage* styleImage(CSSPropertyID, CSSValue*);
     StyleImage* cachedOrPendingFromValue(CSSPropertyID, CSSImageValue*);
+    StyleImage* generatedOrPendingFromValue(CSSPropertyID, CSSImageGeneratorValue*);
 
     bool applyPropertyToRegularStyle() const { return m_applyPropertyToRegularStyle; }
     bool applyPropertyToVisitedLinkStyle() const { return m_applyPropertyToVisitedLinkStyle; }
@@ -340,6 +343,7 @@
     void applySVGProperty(int id, CSSValue*);
 #endif
 
+    StyleImage* loadPendingImage(StylePendingImage*);
     void loadPendingImages();
 
     struct MatchedStyleDeclaration {