2010-08-27  Patrick Gansterer  <paroga@paroga.com>

        Reviewed by Nikolas Zimmermann.

        RenderImage::imageChanged invalidates wrong area
        https://bugs.webkit.org/show_bug.cgi?id=43779

        At the moment RenderSVGImage inherits from RenderImage, which makes non-SVG compatible
        assumptions about repainting, and thus has to be fixed to inherit from RenderSVGModelObject.

        This patch moves the CachedImage from RenderImage into a separate class.
        The new class contains the common behavior of RenderImage and RenderSVGImage.
        An additional patch will remove the inheritance of RenderImage at RenderSVGImage.

        * Android.mk:
        * CMakeLists.txt:
        * GNUmakefile.am:
        * WebCore.gypi:
        * WebCore.pro:
        * WebCore.vcproj/WebCore.vcproj:
        * WebCore.xcodeproj/project.pbxproj:
        * html/HTMLEmbedElement.cpp:
        (WebCore::HTMLEmbedElement::createRenderer):
        (WebCore::HTMLEmbedElement::attach):
        * html/HTMLImageElement.cpp:
        (WebCore::HTMLImageElement::createRenderer):
        (WebCore::HTMLImageElement::attach):
        * html/HTMLInputElement.cpp:
        (WebCore::HTMLInputElement::createRenderer):
        (WebCore::HTMLInputElement::attach):
        * html/HTMLObjectElement.cpp:
        (WebCore::HTMLObjectElement::createRenderer):
        * html/HTMLVideoElement.cpp:
        (WebCore::HTMLVideoElement::attach):
        (WebCore::HTMLVideoElement::parseMappedAttribute):
        * loader/ImageLoader.cpp:
        (WebCore::ImageLoader::setImage):
        (WebCore::ImageLoader::updateFromElement):
        (WebCore::ImageLoader::renderImageResource):
        (WebCore::ImageLoader::updateRenderer):
        * loader/ImageLoader.h:
        * rendering/RenderImage.cpp:
        (WebCore::RenderImage::RenderImage):
        (WebCore::RenderImage::~RenderImage):
        (WebCore::RenderImage::setImageResource):
        (WebCore::RenderImage::imageChanged):
        (WebCore::RenderImage::notifyFinished):
        (WebCore::RenderImage::paintReplaced):
        (WebCore::RenderImage::paintIntoRect):
        (WebCore::RenderImage::minimumReplacedHeight):
        (WebCore::RenderImage::calcReplacedWidth):
        (WebCore::RenderImage::calcReplacedHeight):
        (WebCore::RenderImage::calcAspectRatioWidth):
        (WebCore::RenderImage::calcAspectRatioHeight):
        * rendering/RenderImage.h:
        (WebCore::RenderImage::imageResource):
        (WebCore::RenderImage::cachedImage):
        (WebCore::RenderImage::intrinsicSizeChanged):
        (WebCore::toRenderImage):
        * rendering/RenderImageGeneratedContent.cpp: Removed.
        * rendering/RenderImageGeneratedContent.h: Removed.
        * rendering/RenderImageResource.cpp: Added.
        (WebCore::RenderImageResource::RenderImageResource):
        (WebCore::RenderImageResource::~RenderImageResource):
        (WebCore::RenderImageResource::initialize):
        (WebCore::RenderImageResource::shutdown):
        (WebCore::RenderImageResource::setCachedImage):
        (WebCore::RenderImageResource::resetAnimation):
        (WebCore::RenderImageResource::setImageContainerSize):
        (WebCore::RenderImageResource::nullImage):
        * rendering/RenderImageResource.h: Added.
        (WebCore::RenderImageResource::create):
        (WebCore::RenderImageResource::cachedImage):
        (WebCore::RenderImageResource::hasImage):
        (WebCore::RenderImageResource::image):
        (WebCore::RenderImageResource::errorOccurred):
        (WebCore::RenderImageResource::usesImageContainerSize):
        (WebCore::RenderImageResource::imageHasRelativeWidth):
        (WebCore::RenderImageResource::imageHasRelativeHeight):
        (WebCore::RenderImageResource::imageSize):
        (WebCore::RenderImageResource::imagePtr):
        * rendering/RenderImageResourceStyleImage.cpp: Added.
        (WebCore::RenderImageResourceStyleImage::RenderImageResourceStyleImage):
        (WebCore::RenderImageResourceStyleImage::~RenderImageResourceStyleImage):
        (WebCore::RenderImageResourceStyleImage::initialize):
        (WebCore::RenderImageResourceStyleImage::shutdown):
        * rendering/RenderImageResourceStyleImage.h: Added.
        (WebCore::RenderImageResourceStyleImage::create):
        (WebCore::RenderImageResourceStyleImage::image):
        (WebCore::RenderImageResourceStyleImage::errorOccurred):
        (WebCore::RenderImageResourceStyleImage::setImageContainerSize):
        (WebCore::RenderImageResourceStyleImage::usesImageContainerSize):
        (WebCore::RenderImageResourceStyleImage::imageHasRelativeWidth):
        (WebCore::RenderImageResourceStyleImage::imageHasRelativeHeight):
        (WebCore::RenderImageResourceStyleImage::imageSize):
        (WebCore::RenderImageResourceStyleImage::imagePtr):
        * rendering/RenderMedia.cpp:
        (WebCore::RenderMedia::RenderMedia):
        * rendering/RenderObject.cpp:
        (WebCore::RenderObject::createObject):
        * rendering/RenderObjectChildList.cpp:
        (WebCore::RenderObjectChildList::updateBeforeAfterContent):
        * rendering/RenderSVGImage.cpp:
        (WebCore::RenderSVGImage::RenderSVGImage):
        (WebCore::RenderSVGImage::layout):
        (WebCore::RenderSVGImage::paint):
        * rendering/RenderVideo.cpp:
        (WebCore::RenderVideo::calculateIntrinsicSize):
        * svg/SVGImageElement.cpp:
        (WebCore::SVGImageElement::attach):
        * wml/WMLImageElement.cpp:
        (WebCore::WMLImageElement::createRenderer):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@66223 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp
index 2073479..a7f7df4 100644
--- a/WebCore/rendering/RenderImage.cpp
+++ b/WebCore/rendering/RenderImage.cpp
@@ -57,7 +57,6 @@
 
 RenderImage::RenderImage(Node* node)
     : RenderReplaced(node, IntSize(0, 0))
-    , m_cachedImage(0)
 {
     updateAltText();
 
@@ -66,22 +65,15 @@
 
 RenderImage::~RenderImage()
 {
-    if (m_cachedImage)
-        m_cachedImage->removeClient(this);
+    ASSERT(m_imageResource);
+    m_imageResource->shutdown();
 }
 
-void RenderImage::setCachedImage(CachedImage* newImage)
+void RenderImage::setImageResource(PassOwnPtr<RenderImageResource> imageResource)
 {
-    if (m_cachedImage == newImage)
-        return;
-    if (m_cachedImage)
-        m_cachedImage->removeClient(this);
-    m_cachedImage = newImage;
-    if (m_cachedImage) {
-        m_cachedImage->addClient(this);
-        if (m_cachedImage->errorOccurred())
-            imageChanged(m_cachedImage.get());
-    }
+    ASSERT(!m_imageResource);
+    m_imageResource = imageResource;
+    m_imageResource->initialize(this);
 }
 
 // If we'll be displaying either alt text or an image, add some padding.
@@ -135,22 +127,22 @@
 
     if (hasBoxDecorations() || hasMask())
         RenderReplaced::imageChanged(newImage, rect);
-    
-    if (newImage != imagePtr() || !newImage)
+
+    if (newImage != m_imageResource->imagePtr() || !newImage)
         return;
 
     bool imageSizeChanged = false;
 
     // Set image dimensions, taking into account the size of the alt text.
-    if (errorOccurred())
-        imageSizeChanged = setImageSizeForAltText(m_cachedImage.get());
-    
+    if (m_imageResource->errorOccurred())
+        imageSizeChanged = setImageSizeForAltText(m_imageResource->cachedImage());
+
     bool shouldRepaint = true;
 
     // Image dimensions have been changed, see what needs to be done
-    if (imageSize(style()->effectiveZoom()) != intrinsicSize() || imageSizeChanged) {
-        if (!errorOccurred())
-            setIntrinsicSize(imageSize(style()->effectiveZoom()));
+    if (m_imageResource->imageSize(style()->effectiveZoom()) != intrinsicSize() || imageSizeChanged) {
+        if (!m_imageResource->errorOccurred())
+            setIntrinsicSize(m_imageResource->imageSize(style()->effectiveZoom()));
 
         // In the case of generated image content using :before/:after, we might not be in the
         // render tree yet.  In that case, we don't need to worry about check for layout, since we'll get a
@@ -180,7 +172,7 @@
         if (rect) {
             // The image changed rect is in source image coordinates (pre-zooming),
             // so map from the bounds of the image to the contentsBox.
-            repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), imageSize(1.0f)), contentBoxRect()));
+            repaintRect = enclosingIntRect(mapRect(*rect, FloatRect(FloatPoint(), m_imageResource->imageSize(1.0f)), contentBoxRect()));
             // Guard against too-large changed rects.
             repaintRect.intersect(contentBoxRect());
         } else
@@ -203,7 +195,7 @@
         return;
 
 #if USE(ACCELERATED_COMPOSITING)
-    if ((newImage == m_cachedImage) && hasLayer()) {
+    if (newImage == m_imageResource->cachedImage() && hasLayer()) {
         // tell any potential compositing layers
         // that the image is done and they can reference it directly.
         layer()->rendererContentChanged();
@@ -212,15 +204,6 @@
     UNUSED_PARAM(newImage);
 #endif
 }
-    
-void RenderImage::resetAnimation()
-{
-    if (m_cachedImage) {
-        image()->resetAnimation();
-        if (!needsLayout())
-            repaint();
-    }
-}
 
 void RenderImage::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
 {
@@ -236,7 +219,7 @@
 
     GraphicsContext* context = paintInfo.context;
 
-    if (!hasImage() || errorOccurred()) {
+    if (!m_imageResource->hasImage() || m_imageResource->errorOccurred()) {
         if (paintInfo.phase == PaintPhaseSelection)
             return;
 
@@ -255,17 +238,19 @@
             int usableWidth = cWidth - 2;
             int usableHeight = cHeight - 2;
 
-            if (errorOccurred() && !image()->isNull() && (usableWidth >= image()->width()) && (usableHeight >= image()->height())) {
+            Image* image = m_imageResource->image();
+
+            if (m_imageResource->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) {
                 // Center the error image, accounting for border and padding.
-                int centerX = (usableWidth - image()->width()) / 2;
+                int centerX = (usableWidth - image->width()) / 2;
                 if (centerX < 0)
                     centerX = 0;
-                int centerY = (usableHeight - image()->height()) / 2;
+                int centerY = (usableHeight - image->height()) / 2;
                 if (centerY < 0)
                     centerY = 0;
                 imageX = leftBorder + leftPad + centerX + 1;
                 imageY = topBorder + topPad + centerY + 1;
-                context->drawImage(image(), style()->colorSpace(), IntPoint(tx + imageX, ty + imageY));
+                context->drawImage(image, style()->colorSpace(), IntPoint(tx + imageX, ty + imageY));
                 errorPictureDrawn = true;
             }
 
@@ -288,8 +273,8 @@
                     context->drawText(style()->font(), textRun, IntPoint(ax, ay + ascent));
             }
         }
-    } else if (hasImage() && cWidth > 0 && cHeight > 0) {
-        Image* img = image(cWidth, cHeight);
+    } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) {
+        Image* img = m_imageResource->image(cWidth, cHeight);
         if (!img || img->isNull())
             return;
 
@@ -351,22 +336,22 @@
     
 void RenderImage::paintIntoRect(GraphicsContext* context, const IntRect& rect)
 {
-    if (!hasImage() || errorOccurred() || rect.width() <= 0 || rect.height() <= 0)
+    if (!m_imageResource->hasImage() || m_imageResource->errorOccurred() || rect.width() <= 0 || rect.height() <= 0)
         return;
 
-    Image* img = image(rect.width(), rect.height());
+    Image* img = m_imageResource->image(rect.width(), rect.height());
     if (!img || img->isNull())
         return;
 
     HTMLImageElement* imageElt = (node() && node()->hasTagName(imgTag)) ? static_cast<HTMLImageElement*>(node()) : 0;
     CompositeOperator compositeOperator = imageElt ? imageElt->compositeOperator() : CompositeSourceOver;
-    bool useLowQualityScaling = shouldPaintAtLowQuality(context, this->image(), rect.size());
-    context->drawImage(image(rect.width(), rect.height()), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling);
+    bool useLowQualityScaling = shouldPaintAtLowQuality(context, m_imageResource->image(), rect.size());
+    context->drawImage(m_imageResource->image(rect.width(), rect.height()), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling);
 }
 
 int RenderImage::minimumReplacedHeight() const
 {
-    return errorOccurred() ? intrinsicSize().height() : 0;
+    return m_imageResource->errorOccurred() ? intrinsicSize().height() : 0;
 }
 
 HTMLMapElement* RenderImage::imageMap() const
@@ -449,18 +434,18 @@
 
 int RenderImage::calcReplacedWidth(bool includeMaxWidth) const
 {
-    if (imageHasRelativeWidth())
+    if (m_imageResource->imageHasRelativeWidth())
         if (RenderObject* cb = isPositioned() ? container() : containingBlock()) {
             if (cb->isBox())
-                setImageContainerSize(IntSize(toRenderBox(cb)->availableWidth(), toRenderBox(cb)->availableHeight()));
+                m_imageResource->setImageContainerSize(IntSize(toRenderBox(cb)->availableWidth(), toRenderBox(cb)->availableHeight()));
         }
 
     int width;
     if (isWidthSpecified())
         width = calcReplacedWidthUsing(style()->width());
-    else if (usesImageContainerSize())
-        width = imageSize(style()->effectiveZoom()).width();
-    else if (imageHasRelativeWidth())
+    else if (m_imageResource->usesImageContainerSize())
+        width = m_imageResource->imageSize(style()->effectiveZoom()).width();
+    else if (m_imageResource->imageHasRelativeWidth())
         width = 0; // If the image is relatively-sized, set the width to 0 until there is a set container size.
     else
         width = calcAspectRatioWidth();
@@ -476,9 +461,9 @@
     int height;
     if (isHeightSpecified())
         height = calcReplacedHeightUsing(style()->height());
-    else if (usesImageContainerSize())
-        height = imageSize(style()->effectiveZoom()).height();
-    else if (imageHasRelativeHeight())
+    else if (m_imageResource->usesImageContainerSize())
+        height = m_imageResource->imageSize(style()->effectiveZoom()).height();
+    else if (m_imageResource->imageHasRelativeHeight())
         height = 0; // If the image is relatively-sized, set the height to 0 until there is a set container size.
     else
         height = calcAspectRatioHeight();
@@ -494,7 +479,7 @@
     IntSize size = intrinsicSize();
     if (!size.height())
         return 0;
-    if (!hasImage() || errorOccurred())
+    if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
         return size.width(); // Don't bother scaling.
     return RenderReplaced::calcReplacedHeight() * size.width() / size.height();
 }
@@ -504,7 +489,7 @@
     IntSize size = intrinsicSize();
     if (!size.width())
         return 0;
-    if (!hasImage() || errorOccurred())
+    if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
         return size.height(); // Don't bother scaling.
     return RenderReplaced::calcReplacedWidth() * size.height() / size.width();
 }
@@ -529,9 +514,4 @@
     setPrefWidthsDirty(false);
 }
 
-Image* RenderImage::nullImage()
-{
-    return Image::nullImage();
-}
-
 } // namespace WebCore