<img style='width: 100%' src='foo.svg'> gets pixellated when stretched
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Mar 2012 09:24:46 +0000 (09:24 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Mar 2012 09:24:46 +0000 (09:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=81631

Reviewed by Antti Koivisto.

Source/WebCore:

Final cleanup of RenderReplaced after the intrinsic size negotiation patch series from some weeks/months ago.
Stop tracking whether a RenderReplaced has an intrinsic size or not with an extra-bool, instead assume each
RenderReplaced derived class has an intrinsic size. If not, the class should override
computeIntrinsicRatioInformation() for any custom logic - currently only done by RenderImage.

Remove all logic depending on m_hasIntrinsicSize from computeReplacedLogicalWidth/Height, which was used
to support different sizing models depending on if the replaced element is a RenderImage or a RenderPart.
Unify all of this in computeIntrinsicRatioInformation right in RenderReplaced. This allows to remove
a hack from RenderImage::computeReplacedLogicalWidth(), which forced the synchroniziation of the intrinsicSize()
before calling the base classes RenderReplaced::computeReplacedLogicalWidth().
Now RenderImage just overrides the layout() method, calls RenderReplaced::layout() and then sets the container
size of the image resources to [contentWidth(), contentHeight()] - reflecting the actual result of the layout.
Furthermore this now allows us to unify CachedImage::imageSizeForRenderer() again for both SVG and non-SVG images.

Propagating the right container size to the image resource fixes the actual bug, that the SVGImage got pixellated.
Adding new tests covering percentage width or height set on an <img> embedding an external SVG, no more pixelation.

Tests: svg/as-image/img-relative-height-expected.html
       svg/as-image/img-relative-height.html
       svg/as-image/img-relative-width-expected.html
       svg/as-image/img-relative-width.html

* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::imageSizeForRenderer):
* rendering/RenderEmbeddedObject.cpp:
(WebCore::RenderEmbeddedObject::RenderEmbeddedObject):
* rendering/RenderImage.cpp:
(WebCore::RenderImage::layout):
(WebCore::RenderImage::computeIntrinsicRatioInformation):
* rendering/RenderImage.h:
(RenderImage):
* rendering/RenderReplaced.cpp:
(WebCore::RenderReplaced::RenderReplaced):
(WebCore::rendererHasAspectRatio):
(WebCore):
(WebCore::RenderReplaced::computeIntrinsicRatioInformationForRenderBox):
(WebCore::RenderReplaced::computeIntrinsicRatioInformation):
(WebCore::RenderReplaced::computeReplacedLogicalWidth):
(WebCore::RenderReplaced::computeReplacedLogicalHeight):
* rendering/RenderReplaced.h:
(WebCore::RenderReplaced::intrinsicSize):
(RenderReplaced):
(WebCore::RenderReplaced::setIntrinsicSize):
* svg/graphics/SVGImage.cpp:
(WebCore::SVGImage::setContainerSize):
* svg/graphics/SVGImage.h:
(WebCore::SVGImage::usesContainerSize):

LayoutTests:

Add new tests covering setting only one of width/height to a percentage when embedding SVGs into <img>s.

* platform/chromium/test_expectations.txt: Update expectations.
* platform/mac/fast/repaint/block-layout-inline-children-replaced-expected.txt: Update changed result - slight rounding difference.
* platform/mac/fast/table/quote-text-around-iframe-expected.png: Update changed result, now the default intrinsic size respects scaling.
* platform/mac/fast/table/quote-text-around-iframe-expected.txt: Ditto.
* svg/as-image/img-relative-height-expected.html: Added.
* svg/as-image/img-relative-height.html: Added.
* svg/as-image/img-relative-width-expected.html: Added.
* svg/as-image/img-relative-width.html: Added.
* svg/as-image/resources/island.svg: Added.
* svg/as-image/svg-non-integer-scaled-image-expected.png:
* svg/as-image/svg-non-integer-scaled-image-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@112229 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/test_expectations.txt
LayoutTests/platform/mac/fast/repaint/block-layout-inline-children-replaced-expected.txt
LayoutTests/platform/mac/fast/table/quote-text-around-iframe-expected.png
LayoutTests/platform/mac/fast/table/quote-text-around-iframe-expected.txt
LayoutTests/svg/as-image/img-relative-height-expected.html [new file with mode: 0644]
LayoutTests/svg/as-image/img-relative-height.html [new file with mode: 0644]
LayoutTests/svg/as-image/img-relative-width-expected.html [new file with mode: 0644]
LayoutTests/svg/as-image/img-relative-width.html [new file with mode: 0644]
LayoutTests/svg/as-image/resources/island.svg [new file with mode: 0644]
LayoutTests/svg/as-image/svg-non-integer-scaled-image-expected.png
LayoutTests/svg/as-image/svg-non-integer-scaled-image-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/loader/cache/CachedImage.cpp
Source/WebCore/rendering/RenderEmbeddedObject.cpp
Source/WebCore/rendering/RenderImage.cpp
Source/WebCore/rendering/RenderImage.h
Source/WebCore/rendering/RenderReplaced.cpp
Source/WebCore/rendering/RenderReplaced.h
Source/WebCore/svg/graphics/SVGImage.cpp
Source/WebCore/svg/graphics/SVGImage.h

index 5d15ffb..2f4e601 100644 (file)
@@ -1,3 +1,24 @@
+2012-03-27  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        <img style='width: 100%' src='foo.svg'> gets pixellated when stretched
+        https://bugs.webkit.org/show_bug.cgi?id=81631
+
+        Reviewed by Antti Koivisto.
+
+        Add new tests covering setting only one of width/height to a percentage when embedding SVGs into <img>s.
+
+        * platform/chromium/test_expectations.txt: Update expectations.
+        * platform/mac/fast/repaint/block-layout-inline-children-replaced-expected.txt: Update changed result - slight rounding difference.
+        * platform/mac/fast/table/quote-text-around-iframe-expected.png: Update changed result, now the default intrinsic size respects scaling.
+        * platform/mac/fast/table/quote-text-around-iframe-expected.txt: Ditto.
+        * svg/as-image/img-relative-height-expected.html: Added.
+        * svg/as-image/img-relative-height.html: Added.
+        * svg/as-image/img-relative-width-expected.html: Added.
+        * svg/as-image/img-relative-width.html: Added.
+        * svg/as-image/resources/island.svg: Added.
+        * svg/as-image/svg-non-integer-scaled-image-expected.png:
+        * svg/as-image/svg-non-integer-scaled-image-expected.txt:
+
 2012-03-27  Philippe Normand  <pnormand@igalia.com>
 
         Unreviewed, skip two new xmlhttprequest failures on GTK.
index 65b9626..21ffa48 100644 (file)
@@ -3652,7 +3652,7 @@ BUGWK72761 : accessibility/anonymous-render-block-in-continuation-causes-crash.h
 BUGWK77110 WIN DEBUG : accessibility/loading-iframe-sends-notification.html = PASS TEXT
 
 BUGWK73494 : svg/text/non-bmp-positioning-lists.svg = IMAGE+TEXT IMAGE
-BUGWK73494 : svg/as-image/svg-non-integer-scaled-image.html = IMAGE PASS
+// BUGWK73494 : svg/as-image/svg-non-integer-scaled-image.html = IMAGE PASS
 
 BUGWK73872 LINUX : svg/custom/linking-uri-01-b.svg = PASS TIMEOUT
 
@@ -4131,8 +4131,8 @@ BUGYANGGUO WIN : svg/css/stars-with-shadow.html = TEXT
 BUGWK81325 : fast/canvas/webgl/context-lost.html = TEXT
 
 // Needs rebaseline due to a progression 
-BUGWK43022 WIN : tables/mozilla_expected_failures/bugs/bug85016.html = IMAGE
-BUGWK43022 MAC : tables/mozilla_expected_failures/bugs/bug85016.html = IMAGE+TEXT
+// BUGWK43022 WIN : tables/mozilla_expected_failures/bugs/bug85016.html = IMAGE
+// BUGWK43022 MAC : tables/mozilla_expected_failures/bugs/bug85016.html = IMAGE+TEXT
 
 // flaky tests
 BUGWK81493 LINUX : svg/custom/js-late-gradient-creation.svg = PASS IMAGE
@@ -4206,6 +4206,17 @@ BUGWK37244 : tables/mozilla/bugs/bug27038-2.html = IMAGE+TEXT
 // New test, flaky since added in r110965.
 BUGWK82097 : editing/selection/move-by-word-visually-crash-test-5.html = PASS TIMEOUT
 
+// Just needs a rebaseline. The iframe size is now 600x300, before it was 300x150 - as we properly zoom the default intrinsic size now.
+BUGWK81631 : fast/table/quote-text-around-iframe.html = IMAGE IMAGE+TEXT PASS
+// Size should be 100 now, instead of 101 - if so, only needs a rebaseline.
+BUGWK81631 : svg/as-image/svg-non-integer-scaled-image.html  = IMAGE IMAGE+TEXT PASS
+// Size changed from 93 to 92 due rounding, just needs a rebaseline.
+BUGWK81631 : fast/repaint/block-layout-inline-children-replaced.html = IMAGE IMAGE+TEXT PASS
+// Just needs a rebaseline, no visible changes.
+BUGWK81631 : fast/writing-mode/block-level-images.html = IMAGE IMAGE+TEXT PASS
+// Slight change in image size due to rounding - just needs a rebaseline.
+BUGWK81631 : tables/mozilla_expected_failures/bugs/bug85016.html = IMAGE IMAGE+TEXT PASS
+
 // Temporary: generate platform specific IETestCenter results, then
 // remove when bots produce reference.
 BUGWK81936 : ietestcenter/css3/text/textshadow-001.htm = FAIL MISSING
index 11ff3bd..cc268c6 100644 (file)
@@ -11,4 +11,4 @@ layer at (0,0) size 800x600
             text run at (220,0) width 305: "https://bugs.webkit.org/show_bug.cgi?id=40142"
       RenderBlock {DIV} at (0,34) size 800x152
         RenderBlock {DIV} at (0,0) size 402x152 [border: (1px solid #DDDDDD)]
-          RenderImage {IMG} at (155,1) size 93x100
+          RenderImage {IMG} at (155,1) size 92x100
index 02daed9..7d86191 100644 (file)
Binary files a/LayoutTests/platform/mac/fast/table/quote-text-around-iframe-expected.png and b/LayoutTests/platform/mac/fast/table/quote-text-around-iframe-expected.png differ
index 8b5d1f3..c89a345 100644 (file)
@@ -1,25 +1,25 @@
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
-layer at (0,0) size 800x198
-  RenderBlock {HTML} at (0,0) size 800x198
-    RenderBody {BODY} at (16,16) size 768x166
-      RenderTable at (0,0) size 394x166
-        RenderTableSection (anonymous) at (0,0) size 394x166
-          RenderTableRow {Q} at (0,0) size 394x166
-            RenderTableCell (anonymous) at (0,0) size 394x166 [r=0 c=0 rs=1 cs=1]
+layer at (0,0) size 800x348
+  RenderBlock {HTML} at (0,0) size 800x348
+    RenderBody {BODY} at (16,16) size 768x316
+      RenderTable at (0,0) size 694x316
+        RenderTableSection (anonymous) at (0,0) size 694x316
+          RenderTableRow {Q} at (0,0) size 694x316
+            RenderTableCell (anonymous) at (0,0) size 694x316 [r=0 c=0 rs=1 cs=1]
               RenderInline (generated) at (0,0) size 13x37
-                RenderQuote at (0,129) size 13x37
-                  text run at (0,129) width 13: "\""
-              RenderText {#text} at (13,129) size 31x37
-                text run at (13,129) width 31: " A"
-              RenderPartObject {IFRAME} at (44,0) size 308x158 [border: (4px inset #000000)]
-                layer at (0,0) size 300x150
-                  RenderView at (0,0) size 300x150
-                layer at (0,0) size 300x150
-                  RenderBlock {HTML} at (0,0) size 300x150
-                    RenderBody {BODY} at (8,8) size 284x134
-              RenderText {#text} at (352,129) size 29x37
-                text run at (352,129) width 29: "B "
+                RenderQuote at (0,279) size 13x37
+                  text run at (0,279) width 13: "\""
+              RenderText {#text} at (13,279) size 31x37
+                text run at (13,279) width 31: " A"
+              RenderPartObject {IFRAME} at (44,0) size 608x308 [border: (4px inset #000000)]
+                layer at (0,0) size 600x300
+                  RenderView at (0,0) size 600x300
+                layer at (0,0) size 600x300
+                  RenderBlock {HTML} at (0,0) size 600x300
+                    RenderBody {BODY} at (8,8) size 584x284
+              RenderText {#text} at (652,279) size 29x37
+                text run at (652,279) width 29: "B "
               RenderInline (generated) at (0,0) size 13x37
-                RenderQuote at (381,129) size 13x37
-                  text run at (381,129) width 13: "\""
+                RenderQuote at (681,279) size 13x37
+                  text run at (681,279) width 13: "\""
diff --git a/LayoutTests/svg/as-image/img-relative-height-expected.html b/LayoutTests/svg/as-image/img-relative-height-expected.html
new file mode 100644 (file)
index 0000000..1341ad9
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body style="margin: 0; overflow: hidden;">
+<img style='width: 800px; height: 600px' src='resources/island.svg'>
+</body>
+</html>
diff --git a/LayoutTests/svg/as-image/img-relative-height.html b/LayoutTests/svg/as-image/img-relative-height.html
new file mode 100644 (file)
index 0000000..968bcf8
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body style="margin: 0; height: 600px; overflow: hidden;">
+<img style='height: 100%;' src='resources/island.svg'>
+</body>
+</html>
diff --git a/LayoutTests/svg/as-image/img-relative-width-expected.html b/LayoutTests/svg/as-image/img-relative-width-expected.html
new file mode 100644 (file)
index 0000000..1341ad9
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body style="margin: 0; overflow: hidden;">
+<img style='width: 800px; height: 600px' src='resources/island.svg'>
+</body>
+</html>
diff --git a/LayoutTests/svg/as-image/img-relative-width.html b/LayoutTests/svg/as-image/img-relative-width.html
new file mode 100644 (file)
index 0000000..6f98c27
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body style="margin: 0; overflow: hidden;">
+<img style='width: 100%;' src='resources/island.svg'>
+</body>
+</html>
diff --git a/LayoutTests/svg/as-image/resources/island.svg b/LayoutTests/svg/as-image/resources/island.svg
new file mode 100644 (file)
index 0000000..969a1ce
--- /dev/null
@@ -0,0 +1,3 @@
+<svg width="4" height="3" viewBox='0 0 400 300' xmlns="http://www.w3.org/2000/svg">
+<circle cx="200" cy="150" r="100" fill="green"/>
+</svg>
index a51f330..3392da3 100644 (file)
Binary files a/LayoutTests/svg/as-image/svg-non-integer-scaled-image-expected.png and b/LayoutTests/svg/as-image/svg-non-integer-scaled-image-expected.png differ
index 47bc4c0..c76a473 100644 (file)
@@ -3,5 +3,5 @@ layer at (0,0) size 800x600
 layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (0,0) size 800x600
-      RenderImage {IMG} at (0,0) size 100x101
+      RenderImage {IMG} at (0,0) size 100x100
       RenderText {#text} at (0,0) size 0x0
index 01fbef4..61f7341 100644 (file)
@@ -1,3 +1,58 @@
+2012-03-27  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        <img style='width: 100%' src='foo.svg'> gets pixellated when stretched
+        https://bugs.webkit.org/show_bug.cgi?id=81631
+
+        Reviewed by Antti Koivisto.
+
+        Final cleanup of RenderReplaced after the intrinsic size negotiation patch series from some weeks/months ago.
+        Stop tracking whether a RenderReplaced has an intrinsic size or not with an extra-bool, instead assume each
+        RenderReplaced derived class has an intrinsic size. If not, the class should override
+        computeIntrinsicRatioInformation() for any custom logic - currently only done by RenderImage.
+
+        Remove all logic depending on m_hasIntrinsicSize from computeReplacedLogicalWidth/Height, which was used
+        to support different sizing models depending on if the replaced element is a RenderImage or a RenderPart.
+        Unify all of this in computeIntrinsicRatioInformation right in RenderReplaced. This allows to remove
+        a hack from RenderImage::computeReplacedLogicalWidth(), which forced the synchroniziation of the intrinsicSize()
+        before calling the base classes RenderReplaced::computeReplacedLogicalWidth().
+        Now RenderImage just overrides the layout() method, calls RenderReplaced::layout() and then sets the container
+        size of the image resources to [contentWidth(), contentHeight()] - reflecting the actual result of the layout.
+        Furthermore this now allows us to unify CachedImage::imageSizeForRenderer() again for both SVG and non-SVG images.
+
+        Propagating the right container size to the image resource fixes the actual bug, that the SVGImage got pixellated.
+        Adding new tests covering percentage width or height set on an <img> embedding an external SVG, no more pixelation.
+
+        Tests: svg/as-image/img-relative-height-expected.html
+               svg/as-image/img-relative-height.html
+               svg/as-image/img-relative-width-expected.html
+               svg/as-image/img-relative-width.html
+
+        * loader/cache/CachedImage.cpp:
+        (WebCore::CachedImage::imageSizeForRenderer):
+        * rendering/RenderEmbeddedObject.cpp:
+        (WebCore::RenderEmbeddedObject::RenderEmbeddedObject):
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::layout):
+        (WebCore::RenderImage::computeIntrinsicRatioInformation):
+        * rendering/RenderImage.h:
+        (RenderImage):
+        * rendering/RenderReplaced.cpp:
+        (WebCore::RenderReplaced::RenderReplaced):
+        (WebCore::rendererHasAspectRatio):
+        (WebCore):
+        (WebCore::RenderReplaced::computeIntrinsicRatioInformationForRenderBox):
+        (WebCore::RenderReplaced::computeIntrinsicRatioInformation):
+        (WebCore::RenderReplaced::computeReplacedLogicalWidth):
+        (WebCore::RenderReplaced::computeReplacedLogicalHeight):
+        * rendering/RenderReplaced.h:
+        (WebCore::RenderReplaced::intrinsicSize):
+        (RenderReplaced):
+        (WebCore::RenderReplaced::setIntrinsicSize):
+        * svg/graphics/SVGImage.cpp:
+        (WebCore::SVGImage::setContainerSize):
+        * svg/graphics/SVGImage.h:
+        (WebCore::SVGImage::usesContainerSize):
+
 2012-03-27  Ilya Tikhonovsky  <loislo@chromium.org>
 
         Web Inspector: HeapSnapshot: speed-up distanceToWindow calculation.
index e81a1b8..1b5969d 100644 (file)
@@ -240,34 +240,29 @@ IntSize CachedImage::imageSizeForRenderer(const RenderObject* renderer, float mu
 
     if (!m_image)
         return IntSize();
+
+    IntSize imageSize = m_image->size();
+
 #if ENABLE(SVG)
     if (m_image->isSVGImage()) {
-        // SVGImages already includes the zooming in its intrinsic size.
         SVGImageCache::SizeAndZoom sizeAndZoom = m_svgImageCache->requestedSizeAndZoom(renderer);
-        if (sizeAndZoom.size.isEmpty())
-            return m_image->size();
-        if (sizeAndZoom.zoom == 1)
-            return sizeAndZoom.size;
-        if (multiplier == 1) {
-            // Consumer wants unscaled coordinates.
-            sizeAndZoom.size.setWidth(sizeAndZoom.size.width() / sizeAndZoom.zoom);
-            sizeAndZoom.size.setHeight(sizeAndZoom.size.height() / sizeAndZoom.zoom);
-            return sizeAndZoom.size;
+        if (!sizeAndZoom.size.isEmpty()) {
+            imageSize.setWidth(sizeAndZoom.size.width() / sizeAndZoom.zoom);
+            imageSize.setHeight(sizeAndZoom.size.height() / sizeAndZoom.zoom);
         }
-        return sizeAndZoom.size;
     }
 #else
     UNUSED_PARAM(renderer);
 #endif
 
     if (multiplier == 1.0f)
-        return m_image->size();
+        return imageSize;
         
     // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
-    bool hasWidth = m_image->size().width() > 0;
-    bool hasHeight = m_image->size().height() > 0;
-    int width = m_image->size().width() * (m_image->hasRelativeWidth() ? 1.0f : multiplier);
-    int height = m_image->size().height() * (m_image->hasRelativeHeight() ? 1.0f : multiplier);
+    bool hasWidth = imageSize.width() > 0;
+    bool hasHeight = imageSize.height() > 0;
+    int width = imageSize.width() * (m_image->hasRelativeWidth() ? 1.0f : multiplier);
+    int height = imageSize.height() * (m_image->hasRelativeHeight() ? 1.0f : multiplier);
     if (hasWidth)
         width = max(1, width);
     if (hasHeight)
index c239db2..99b4f72 100644 (file)
 #include "Text.h"
 #include "TextRun.h"
 
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-#include "HTMLVideoElement.h"
-#endif
-
 namespace WebCore {
 
 using namespace HTMLNames;
@@ -83,10 +79,6 @@ RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
     , m_mouseDownWasInMissingPluginIndicator(false)
 {
     view()->frameView()->setIsVisuallyNonEmpty();
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
-    if (element->hasTagName(videoTag) || element->hasTagName(audioTag))
-        setHasIntrinsicSize();
-#endif
 }
 
 RenderEmbeddedObject::~RenderEmbeddedObject()
index 4d588b9..be2e1a6 100644 (file)
@@ -6,6 +6,7 @@
  *           (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
  * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -503,52 +504,34 @@ void RenderImage::updateAltText()
         m_altText = static_cast<HTMLImageElement*>(node())->altText();
 }
 
-LayoutUnit RenderImage::computeReplacedLogicalWidth(bool includeMaxWidth) const
+void RenderImage::layout()
 {
-    // If we've got an explicit width/height assigned, propagate it to the image resource.
-    if (style()->logicalWidth().isSpecified() && style()->logicalHeight().isSpecified()) {
-        LayoutUnit width = RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth);
-        m_imageResource->setContainerSizeForRenderer(IntSize(width, computeReplacedLogicalHeight()));
-        return width;
-    }
+    RenderReplaced::layout();
 
-    IntSize containerSize;
-    if (m_imageResource->imageHasRelativeWidth() || m_imageResource->imageHasRelativeHeight()) {
-        // Propagate the containing block size to the image resource, otherwhise we can't compute our own intrinsic size, if it's relative.
-        RenderObject* containingBlock = isPositioned() ? container() : this->containingBlock();
-        if (containingBlock->isBox()) {
-            RenderBox* box = toRenderBox(containingBlock);
-            containerSize = IntSize(box->availableWidth(), box->availableHeight()); // Already contains zooming information.
-        }
-    } else {
-        // Propagate the current zoomed image size to the image resource, otherwhise the image size will remain the same on-screen.
-        CachedImage* cachedImage = m_imageResource->cachedImage();
-        if (cachedImage && cachedImage->image()) {
-            containerSize = cachedImage->image()->size();
-            // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656
-            containerSize.setWidth(roundToInt(containerSize.width() * style()->effectiveZoom()));
-            containerSize.setHeight(roundToInt(containerSize.height() * style()->effectiveZoom()));
-        }
-    }
-
-    if (!containerSize.isEmpty()) {
+    // Propagate container size to image resource.
+    IntSize containerSize(contentWidth(), contentHeight());
+    if (!containerSize.isEmpty())
         m_imageResource->setContainerSizeForRenderer(containerSize);
-        const_cast<RenderImage*>(this)->updateIntrinsicSizeIfNeeded(containerSize, false);
-    }
-
-    return RenderReplaced::computeReplacedLogicalWidth(includeMaxWidth);
 }
 
 void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const
 {
-    // Assure this method is never used for SVGImages.
-    ASSERT(!embeddedContentBox());
-    isPercentageIntrinsicSize = false;
-    CachedImage* cachedImage = m_imageResource ? m_imageResource->cachedImage() : 0;
-    if (!cachedImage || !cachedImage->image())
+    RenderReplaced::computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
+
+    // Our intrinsicSize is empty if we're rendering generated images with relative width/height. Figure out the right intrinsic size to use.
+    if (intrinsicSize.isEmpty() && (m_imageResource->imageHasRelativeWidth() || m_imageResource->imageHasRelativeHeight())) {
+        RenderObject* containingBlock = isPositioned() ? container() : this->containingBlock();
+        if (containingBlock->isBox()) {
+            RenderBox* box = toRenderBox(containingBlock);
+            intrinsicSize.setWidth(box->availableLogicalWidth());
+            intrinsicSize.setHeight(box->availableLogicalHeight());
+        }
+    }
+    // Don't compute an intrinsic ratio to preserve historical WebKit behavior if we're painting alt text and/or a broken image.
+    if (m_imageResource && m_imageResource->errorOccurred()) {
+        intrinsicRatio = 1;
         return;
-    intrinsicSize = cachedImage->image()->size();
-    intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height());
+    }
 }
 
 bool RenderImage::needsPreferredWidthsRecalculation() const
index b9ba753..11197cc 100644 (file)
@@ -68,6 +68,7 @@ protected:
 
     virtual void paintIntoRect(GraphicsContext*, const LayoutRect&);
     virtual void paint(PaintInfo&, const LayoutPoint&);
+    virtual void layout();
 
     virtual void intrinsicSizeChanged()
     {
@@ -90,8 +91,6 @@ private:
     virtual void notifyFinished(CachedResource*);
     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction);
 
-    virtual LayoutUnit computeReplacedLogicalWidth(bool includeMaxWidth = true) const;
-
     IntSize imageSizeForError(CachedImage*) const;
     void imageDimensionsChanged(bool imageSizeChanged, const IntRect* = 0);
     bool updateIntrinsicSizeIfNeeded(const IntSize&, bool imageSizeChanged);
index cf8054b..4a27b8b 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Dirk Mueller (mueller@kde.org)
  * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -43,7 +44,6 @@ const int cDefaultHeight = 150;
 RenderReplaced::RenderReplaced(Node* node)
     : RenderBox(node)
     , m_intrinsicSize(cDefaultWidth, cDefaultHeight)
-    , m_hasIntrinsicSize(false)
 {
     setReplaced(true);
 }
@@ -51,7 +51,6 @@ RenderReplaced::RenderReplaced(Node* node)
 RenderReplaced::RenderReplaced(Node* node, const IntSize& intrinsicSize)
     : RenderBox(node)
     , m_intrinsicSize(intrinsicSize)
-    , m_hasIntrinsicSize(true)
 {
     setReplaced(true);
 }
@@ -202,24 +201,6 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintO
     return true;
 }
 
-int RenderReplaced::computeIntrinsicLogicalWidth(RenderBox* contentRenderer, bool includeMaxWidth) const
-{
-    if (m_hasIntrinsicSize)
-        return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth);
-    ASSERT(contentRenderer);
-    ASSERT(contentRenderer->style());
-    return contentRenderer->computeReplacedLogicalWidthRespectingMinMaxWidth(contentRenderer->computeReplacedLogicalWidthUsing(contentRenderer->style()->logicalWidth()), includeMaxWidth);
-}
-
-int RenderReplaced::computeIntrinsicLogicalHeight(RenderBox* contentRenderer) const
-{
-    if (m_hasIntrinsicSize)
-        return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight());
-    ASSERT(contentRenderer);
-    ASSERT(contentRenderer->style());
-    return contentRenderer->computeReplacedLogicalHeightRespectingMinMaxHeight(contentRenderer->computeReplacedLogicalHeightUsing(contentRenderer->style()->logicalHeight()));
-}
-
 static inline RenderBlock* firstContainingBlockWithLogicalWidth(const RenderReplaced* replaced)
 {
     // We have to lookup the containing block, which has an explicit width, which must not be equal to our direct containing block.
@@ -282,6 +263,56 @@ bool RenderReplaced::hasReplacedLogicalHeight() const
     return false;
 }
 
+static inline bool rendererHasAspectRatio(const RenderObject* renderer)
+{
+    ASSERT(renderer);
+    return renderer->isImage() || renderer->isCanvas() || renderer->isVideo();
+}
+
+void RenderReplaced::computeIntrinsicRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const
+{
+    if (contentRenderer) {
+        contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
+        if (intrinsicRatio)
+            ASSERT(!isPercentageIntrinsicSize);
+
+        // Handle zoom & vertical writing modes here, as the embedded document doesn't know about them.
+        if (!isPercentageIntrinsicSize)
+            intrinsicSize.scale(style()->effectiveZoom());
+
+        if (intrinsicRatio && !isHorizontalWritingMode())
+            intrinsicRatio = 1 / intrinsicRatio;
+
+        if (rendererHasAspectRatio(this) && isPercentageIntrinsicSize)
+            intrinsicRatio = 1;
+        return;
+    }
+
+    // This code path can't yield percentage intrinsic sizes, assert that.
+    computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
+    ASSERT(!isPercentageIntrinsicSize);
+}
+
+void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const
+{
+    // If there's an embeddedContentBox() of a remote, referenced document available, this code-path should never be used.
+    ASSERT(!embeddedContentBox());
+    isPercentageIntrinsicSize = false;
+    intrinsicSize = FloatSize(intrinsicLogicalWidth(), intrinsicLogicalHeight());
+
+    // Figure out if we need to compute an intrinsic ratio.
+    if (intrinsicSize.isEmpty() || !rendererHasAspectRatio(this))
+        return;
+
+    intrinsicRatio = intrinsicSize.width() / intrinsicSize.height();
+    if (style()->logicalWidth().isAuto() && style()->logicalHeight().isAuto()) {
+        // We can't multiply or divide by 'intrinsicRatio' here, it breaks tests, like fast/images/zoomed-img-size.html, which
+        // can only be fixed once subpixel precision is available for things like intrinsicWidth/Height - which include zoom!
+        intrinsicSize.setWidth(RenderBox::computeReplacedLogicalHeight() * intrinsicLogicalWidth() / intrinsicLogicalHeight());
+        intrinsicSize.setHeight(RenderBox::computeReplacedLogicalWidth() * intrinsicLogicalHeight() / intrinsicLogicalWidth());
+    }
+}
+
 LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) const
 {
     if (style()->logicalWidth().isSpecified())
@@ -293,33 +324,25 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con
     bool isPercentageIntrinsicSize = false;
     double intrinsicRatio = 0;
     FloatSize intrinsicSize;
-    if (contentRenderer)
-        contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
-    else
-        computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
-
-    if (intrinsicRatio && !isHorizontalWritingMode())
-        intrinsicRatio = 1 / intrinsicRatio;
+    computeIntrinsicRatioInformationForRenderBox(contentRenderer, intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
 
+    // FIXME: Remove unnecessary round/roundToInt calls from this method when layout is off ints: webkit.org/b/63656
     if (style()->logicalWidth().isAuto()) {
         bool heightIsAuto = style()->logicalHeight().isAuto();
-        bool hasIntrinsicWidth = m_hasIntrinsicSize || (!isPercentageIntrinsicSize && intrinsicSize.width() > 0);
+        bool hasIntrinsicWidth = !isPercentageIntrinsicSize && intrinsicSize.width() > 0;
 
         // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, then that intrinsic width is the used value of 'width'.
-        if (heightIsAuto && hasIntrinsicWidth) {
-            if (m_hasIntrinsicSize)
-                return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth);
-            return static_cast<LayoutUnit>(intrinsicSize.width() * style()->effectiveZoom());
-        }
+        if (heightIsAuto && hasIntrinsicWidth)
+            return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(intrinsicSize.width()), includeMaxWidth);
 
-        bool hasIntrinsicHeight = m_hasIntrinsicSize || (!isPercentageIntrinsicSize && intrinsicSize.height() > 0);
+        bool hasIntrinsicHeight = !isPercentageIntrinsicSize && intrinsicSize.height() > 0;
         if (intrinsicRatio || isPercentageIntrinsicSize) {
             // If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, but does have an intrinsic height and intrinsic ratio;
             // or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value
             // of 'width' is: (used height) * (intrinsic ratio)
             if (intrinsicRatio && ((heightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !heightIsAuto)) {
                 LayoutUnit logicalHeight = computeReplacedLogicalHeightUsing(style()->logicalHeight());
-                return computeReplacedLogicalWidthRespectingMinMaxWidth(static_cast<LayoutUnit>(ceil(logicalHeight * intrinsicRatio)));
+                return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(round(logicalHeight * intrinsicRatio)));
             }
 
             // If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width, then the used value of
@@ -339,22 +362,20 @@ LayoutUnit RenderReplaced::computeReplacedLogicalWidth(bool includeMaxWidth) con
                 LayoutUnit marginEnd = minimumValueForLength(style()->marginEnd(), logicalWidth);
                 logicalWidth = max(0, logicalWidth - (marginStart + marginEnd + (width() - clientWidth())));
                 if (isPercentageIntrinsicSize)
-                    // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656
-                    logicalWidth = static_cast<LayoutUnit>(round(logicalWidth * intrinsicSize.width() / 100));
-                return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth);
+                    logicalWidth = roundToInt(logicalWidth * intrinsicSize.width() / 100);
+                return computeReplacedLogicalWidthRespectingMinMaxWidth(logicalWidth, includeMaxWidth);
             }
         }
 
         // Otherwise, if 'width' has a computed value of 'auto', and the element has an intrinsic width, then that intrinsic width is the used value of 'width'.
-        if (hasIntrinsicWidth) {
-            if (isPercentageIntrinsicSize || m_hasIntrinsicSize)
-                return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth);
-            return static_cast<LayoutUnit>(intrinsicSize.width() * style()->effectiveZoom());
-        }
+        if (hasIntrinsicWidth)
+            return computeReplacedLogicalWidthRespectingMinMaxWidth(roundToInt(intrinsicSize.width()), includeMaxWidth);
 
         // Otherwise, if 'width' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'width' becomes 300px. If 300px is too
         // wide to fit the device, UAs should use the width of the largest rectangle that has a 2:1 ratio and fits the device instead.
-        return computeReplacedLogicalWidthRespectingMinMaxWidth(cDefaultWidth, includeMaxWidth);
+        // Note: We fall through and instead return intrinsicLogicalWidth() here - to preserve existing WebKit behavior, which might or might not be correct, or desired.
+        // Changing this to return cDefaultWidth, will affect lots of test results. Eg. some tests assume that a blank <img> tag (which implies width/height=auto)
+        // has no intrinsic size, which is wrong per CSS 2.1, but matches our behavior since a long time.
     }
 
     return computeReplacedLogicalWidthRespectingMinMaxWidth(intrinsicLogicalWidth(), includeMaxWidth);
@@ -372,59 +393,28 @@ LayoutUnit RenderReplaced::computeReplacedLogicalHeight() const
     bool isPercentageIntrinsicSize = false;
     double intrinsicRatio = 0;
     FloatSize intrinsicSize;
-    if (contentRenderer)
-        contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
-    else
-        computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
-
-    if (intrinsicRatio && !isHorizontalWritingMode())
-        intrinsicRatio = 1 / intrinsicRatio;
+    computeIntrinsicRatioInformationForRenderBox(contentRenderer, intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
 
+    // FIXME: Remove unnecessary round/roundToInt calls from this method when layout is off ints: webkit.org/b/63656
     bool widthIsAuto = style()->logicalWidth().isAuto();
-    bool hasIntrinsicHeight = m_hasIntrinsicSize || (!isPercentageIntrinsicSize && intrinsicSize.height() > 0);
+    bool hasIntrinsicHeight = !isPercentageIntrinsicSize && intrinsicSize.height() > 0;
 
     // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic height, then that intrinsic height is the used value of 'height'.
-    if (widthIsAuto && hasIntrinsicHeight) {
-        if (m_hasIntrinsicSize)
-            return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight());
-        return static_cast<LayoutUnit>(intrinsicSize.height() * style()->effectiveZoom());
-    }
+    if (widthIsAuto && hasIntrinsicHeight)
+        return computeReplacedLogicalHeightRespectingMinMaxHeight(roundToInt(intrinsicSize.height()));
 
     // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is:
     // (used width) / (intrinsic ratio)
-    if (intrinsicRatio && !isPercentageIntrinsicSize) {
-        // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656
-        return computeReplacedLogicalHeightRespectingMinMaxHeight(round(availableLogicalWidth() / intrinsicRatio));
-    }
+    if (intrinsicRatio)
+        return computeReplacedLogicalHeightRespectingMinMaxHeight(roundToInt(round(availableLogicalWidth() / intrinsicRatio)));
 
     // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'.
-    if (hasIntrinsicHeight) {
-        if (m_hasIntrinsicSize)
-            return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight());
-        return static_cast<LayoutUnit>(intrinsicSize.height() * style()->effectiveZoom());
-    }
+    if (hasIntrinsicHeight)
+        return computeReplacedLogicalHeightRespectingMinMaxHeight(roundToInt(intrinsicSize.height()));
 
     // Otherwise, if 'height' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'height' must be set to the height
     // of the largest rectangle that has a 2:1 ratio, has a height not greater than 150px, and has a width not greater than the device width.
-    return computeReplacedLogicalHeightRespectingMinMaxHeight(cDefaultHeight);
-}
-
-int RenderReplaced::calcAspectRatioLogicalWidth() const
-{
-    int intrinsicWidth = intrinsicLogicalWidth();
-    int intrinsicHeight = intrinsicLogicalHeight();
-    if (!intrinsicHeight)
-        return 0;
-    return RenderBox::computeReplacedLogicalHeight() * intrinsicWidth / intrinsicHeight;
-}
-
-int RenderReplaced::calcAspectRatioLogicalHeight() const
-{
-    int intrinsicWidth = intrinsicLogicalWidth();
-    int intrinsicHeight = intrinsicLogicalHeight();
-    if (!intrinsicWidth)
-        return 0;
-    return RenderBox::computeReplacedLogicalWidth() * intrinsicHeight / intrinsicWidth;
+    return computeReplacedLogicalHeightRespectingMinMaxHeight(intrinsicLogicalHeight());
 }
 
 void RenderReplaced::computePreferredLogicalWidths()
@@ -537,17 +527,6 @@ bool RenderReplaced::isSelected() const
     return false;
 }
 
-IntSize RenderReplaced::intrinsicSize() const
-{
-    return m_intrinsicSize;
-}
-
-void RenderReplaced::setIntrinsicSize(const IntSize& size)
-{
-    ASSERT(m_hasIntrinsicSize);
-    m_intrinsicSize = size;
-}
-
 LayoutRect RenderReplaced::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
 {
     if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
index c0ba97d..9ebc634 100644 (file)
@@ -43,7 +43,8 @@ protected:
 
     virtual void layout();
 
-    virtual IntSize intrinsicSize() const;
+    virtual IntSize intrinsicSize() const { return m_intrinsicSize; }
+    virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const;
 
     virtual int minimumReplacedHeight() const { return 0; }
 
@@ -53,9 +54,8 @@ protected:
 
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
 
-    void setIntrinsicSize(const IntSize&);
+    void setIntrinsicSize(const IntSize& intrinsicSize) { m_intrinsicSize = intrinsicSize; }
     virtual void intrinsicSizeChanged();
-    void setHasIntrinsicSize() { m_hasIntrinsicSize = true; }
 
     virtual void paint(PaintInfo&, const LayoutPoint&);
     bool shouldPaint(PaintInfo&, const LayoutPoint&);
@@ -63,18 +63,11 @@ protected:
 
 private:
     virtual RenderBox* embeddedContentBox() const { return 0; }
-    int computeIntrinsicLogicalWidth(RenderBox* contentRenderer, bool includeMaxWidth) const;
-    int computeIntrinsicLogicalHeight(RenderBox* contentRenderer) const;
-
     virtual const char* renderName() const { return "RenderReplaced"; }
 
     virtual bool canHaveChildren() const { return false; }
 
     virtual void computePreferredLogicalWidths();
-
-    int calcAspectRatioLogicalWidth() const;
-    int calcAspectRatioLogicalHeight() const;
-
     virtual void paintReplaced(PaintInfo&, const LayoutPoint&) { }
 
     virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const;
@@ -84,9 +77,9 @@ private:
     virtual bool canBeSelectionLeaf() const { return true; }
 
     virtual LayoutRect selectionRectForRepaint(RenderBoxModelObject* repaintContainer, bool clipToVisibleContent = true);
+    void computeIntrinsicRatioInformationForRenderBox(RenderBox*, FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const;
 
     IntSize m_intrinsicSize;
-    bool m_hasIntrinsicSize;
 };
 
 }
index 45ea294..d35028a 100644 (file)
@@ -102,22 +102,10 @@ SVGImage::~SVGImage()
 
 void SVGImage::setContainerSize(const IntSize&)
 {
+    // SVGImageCache already intercepted this call, as it stores & caches the desired container sizes & zoom levels.
     ASSERT_NOT_REACHED();
 }
 
-bool SVGImage::usesContainerSize() const
-{
-    if (!m_page)
-        return false;
-    Frame* frame = m_page->mainFrame();
-    SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement();
-    if (!rootElement)
-        return false;
-    if (RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer()))
-        return !renderer->containerSize().isEmpty();
-    return false;
-}
-
 IntSize SVGImage::size() const
 {
     if (!m_page)
index bc8d16a..12c1bc9 100644 (file)
@@ -69,7 +69,7 @@ private:
     virtual String filenameExtension() const;
 
     virtual void setContainerSize(const IntSize&);
-    virtual bool usesContainerSize() const;
+    virtual bool usesContainerSize() const { return true; }
     virtual void computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio, float scaleFactor = 1);
 
     virtual bool dataChanged(bool allDataReceived);