2011-11-08 Nikolas Zimmermann <nzimmermann@rim.com>
authorzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 Nov 2011 09:32:52 +0000 (09:32 +0000)
committerzimmermann@webkit.org <zimmermann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 Nov 2011 09:32:52 +0000 (09:32 +0000)
        Switch SVGImage cache to store ImageBuffers instead of whole SVGImages, including a DOM/Render tree
        https://bugs.webkit.org/show_bug.cgi?id=71368

        Reviewed by Antti Koivisto.

        Add some layout tests covering repainting of embedded SVG documents triggered by SMIL animations.

        * platform/chromium/test_expectations.txt: Fix test expectations, as described in bug 71226.
        * platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.png: Added.
        * platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.txt: Added.
        * platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.png: Added.
        * platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.txt: Added.
        * svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html: Added.
        * svg/as-image/animated-svg-as-image-same-image.html: Added.
        * svg/as-image/resources/animated-rect-same-image.svg: Copied from LayoutTests/svg/as-image/resources/animated-rect-fixed-size.svg.
        * svg/zoom/page/zoom-coords-viewattr-01-b.svg: Add comment, why scrollbars shouldn't appear anymore here.

2011-11-08  Nikolas Zimmermann  <nzimmermann@rim.com>

        Switch SVGImage cache to store ImageBuffers instead of whole SVGImages, including a DOM/Render tree
        https://bugs.webkit.org/show_bug.cgi?id=71368

        Reviewed by Antti Koivisto.

        Fix regressions/races introduced by r98852. SVGImage repainting didn't work under certain circumstances.
        The problem was hard to reproduce on Mac ports, but easily visible on Chromium, when opening two files
        that shared the same animated SVG image. The problem of sharing a single ImageObserver across multiple
        instances of the same SVGImage, leads to nasty problems, that are timing dependant. changedInRect() calls
        that should only by received in one document, are received in the other as well, due the shared nature
        of CachedImage. To avoid these problems alltogether, a new approach is needed, that was initially suggested
        by Antti.

        Avoid creating multiple SVGImages and caching them for different sizes/zoom levels. Introduce SVGImageCache
        which holds rendered versions of the SVGImage at certain sizes/zoom levels. It holds (ImageBuffer, Image) pairs
        for each renderer, associated with a size and zoom level.

        This is a major change to the cache as introduced some weeks ago. Instead of holding multiple SVGImages, each containing
        a whole DOM/render tree, we now create bitmap images rendered at the requested sizes/zoom levels and cache them.

        Revert ImageBySizeCache changes that were needed to make it usable wih SVGImage. Its now used only in CSSImageGeneratorValue and
        thus the extra information that CSSImageGeneratorValue doesn't need can be removed again (desired/actual size differentations, and the zoom level).

        Tests: svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html
               svg/as-image/animated-svg-as-image-same-image.html

        * CMakeLists.txt: Add svg/graphics/SVGImageCache.* to build.
        * GNUmakefile.list.am: Ditto.
        * Target.pri: Ditto.
        * WebCore.gypi: Ditto.
        * WebCore.vcproj/WebCore.vcproj: Ditto.
        * WebCore.vcproj/copyForwardingHeaders.cmd: Copy headers from svg/graphics, as SVGImageCache is needed by CachedImage in SVG enabled builds.
        * WebCore.xcodeproj/project.pbxproj: Add svg/graphics/SVGImageCache.* to build.
        * css/CSSImageGeneratorValue.cpp: Remove zoom parameter from addClient/getImage, no need to pass 1 default values anymore.
        (WebCore::CSSImageGeneratorValue::addClient):
        (WebCore::CSSImageGeneratorValue::getImage):
        * loader/cache/CachedImage.cpp: Stop using ImageBySizeCache, and switch to the new SVGImageCache.
        (WebCore::CachedImage::removeClientForRenderer):
        (WebCore::CachedImage::lookupOrCreateImageForRenderer):
        (WebCore::CachedImage::setContainerSizeForRenderer):
        (WebCore::CachedImage::imageSizeForRenderer):
        (WebCore::CachedImage::clear):
        (WebCore::CachedImage::createImage):
        (WebCore::CachedImage::destroyDecodedData):
        (WebCore::CachedImage::decodedSizeChanged):
        (WebCore::CachedImage::didDraw):
        (WebCore::CachedImage::shouldPauseAnimation):
        (WebCore::CachedImage::animationAdvanced):
        (WebCore::CachedImage::changedInRect):
        * loader/cache/CachedImage.h:
        * page/DragController.cpp: Stop using imageForRenderer(), as it may return cached BitmapImages, that don't carry a filename extension anymore, which is required here.
        (WebCore::getImage):
        * rendering/ImageBySizeCache.cpp: Revert changes to ImageBySizeCache, which were needed to make it usable for SVGImages. CSSImageGenerator doesn't need it.
        (WebCore::ImageBySizeCache::addClient):
        (WebCore::ImageBySizeCache::removeClient):
        (WebCore::ImageBySizeCache::getImage):
        * rendering/ImageBySizeCache.h: Ditto.
        (WebCore::SizeAndCount::SizeAndCount):
        * rendering/RenderImage.cpp: Stop using imageForRenderer(), use cachedImage()->image(), which is guaranteed to be a SVGImage for svg images, and not a cached bitmap copy.
        (WebCore::RenderImage::embeddedContentBox):
        * rendering/RenderReplaced.cpp: Simplify logic to figure out the intrinsic size - the special logic for the old SVGImage cache can go away now.
        (WebCore::RenderReplaced::computeIntrinsicLogicalWidth):
        (WebCore::RenderReplaced::computeIntrinsicLogicalHeight):
        * rendering/style/StyleCachedImage.cpp: Call removeClientForRenderer(), which takes care of clearing SVGImageCache entries as well.
        (WebCore::StyleCachedImage::removeClient): This change is needed, as we don't want to make removeClient() virtual in CachedResource.
        * rendering/svg/RenderSVGRoot.cpp: Rename isEmbeddedThroughImageElement to isEmbeddedThroughSVGImage, as this is what it actually checks.
        (WebCore::RenderSVGRoot::isEmbeddedThroughSVGImage):
        * rendering/svg/RenderSVGRoot.h:
        * svg/SVGSVGElement.cpp: Fix bug that's visible now with the SVGImageCache, which was already there before, but hard to trigger.
        (WebCore::SVGSVGElement::currentViewBoxRect): The viewBox depends on who's asking for it: the host document or the embedded document? Take that into account.
        * svg/SVGSVGElement.h:
        * svg/graphics/SVGImage.cpp: Cleanup some code. Add new logic that draws a SVGImage into an ImageBuffer at a desired size & zoom.
        (WebCore::SVGImage::setContainerSize):
        (WebCore::SVGImage::size):
        (WebCore::SVGImage::drawSVGToImageBuffer):
        * svg/graphics/SVGImage.h:
        * svg/graphics/SVGImageCache.cpp: Added. SVGImageCache caches Image/ImageBuffer pairs for each _renderer_ and size/zoom level. The ImageBySizeCache only cared about size.
        (WebCore::SVGImageCache::SVGImageCache):
        (WebCore::SVGImageCache::~SVGImageCache):
        (WebCore::SVGImageCache::removeRendererFromCache):
        (WebCore::SVGImageCache::setRequestedSizeAndZoom):
        (WebCore::SVGImageCache::getRequestedSizeAndZoom):
        (WebCore::SVGImageCache::imageContentChanged):
        (WebCore::SVGImageCache::redrawTimerFired):
        (WebCore::SVGImageCache::lookupOrCreateBitmapImageForRenderer):
        * svg/graphics/SVGImageCache.h: Added.
        (WebCore::SVGImageCache::create):
        (WebCore::SVGImageCache::CachedSizeAndZoom::CachedSizeAndZoom):
        (WebCore::SVGImageCache::CachedImageData::CachedImageData):

2011-11-08  Nikolas Zimmermann  <nzimmermann@rim.com>

        Switch SVGImage cache to store ImageBuffers instead of whole SVGImages, including a DOM/Render tree
        https://bugs.webkit.org/show_bug.cgi?id=71368

        Reviewed by Antti Koivisto.

        * CMakeLists.txt: Add svg/graphics include, for SVGImageCache.h.

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

37 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/test_expectations.txt
LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.png [new file with mode: 0644]
LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.txt [new file with mode: 0644]
LayoutTests/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html [new file with mode: 0644]
LayoutTests/svg/as-image/animated-svg-as-image-same-image.html [new file with mode: 0644]
LayoutTests/svg/as-image/resources/animated-rect-same-image.svg [new file with mode: 0644]
LayoutTests/svg/zoom/page/zoom-coords-viewattr-01-b.svg
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.vcproj/copyForwardingHeaders.cmd
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSImageGeneratorValue.cpp
Source/WebCore/loader/cache/CachedImage.cpp
Source/WebCore/loader/cache/CachedImage.h
Source/WebCore/page/DragController.cpp
Source/WebCore/rendering/ImageBySizeCache.cpp
Source/WebCore/rendering/ImageBySizeCache.h
Source/WebCore/rendering/RenderImage.cpp
Source/WebCore/rendering/RenderReplaced.cpp
Source/WebCore/rendering/style/StyleCachedImage.cpp
Source/WebCore/rendering/svg/RenderSVGRoot.cpp
Source/WebCore/rendering/svg/RenderSVGRoot.h
Source/WebCore/svg/SVGSVGElement.cpp
Source/WebCore/svg/SVGSVGElement.h
Source/WebCore/svg/graphics/SVGImage.cpp
Source/WebCore/svg/graphics/SVGImage.h
Source/WebCore/svg/graphics/SVGImageCache.cpp [new file with mode: 0644]
Source/WebCore/svg/graphics/SVGImageCache.h [new file with mode: 0644]
Source/WebKit/CMakeLists.txt
Source/WebKit/ChangeLog

index cc51219..fe4a138 100644 (file)
@@ -1,3 +1,22 @@
+2011-11-08  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        Switch SVGImage cache to store ImageBuffers instead of whole SVGImages, including a DOM/Render tree
+        https://bugs.webkit.org/show_bug.cgi?id=71368
+
+        Reviewed by Antti Koivisto.
+
+        Add some layout tests covering repainting of embedded SVG documents triggered by SMIL animations.
+
+        * platform/chromium/test_expectations.txt: Fix test expectations, as described in bug 71226.
+        * platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.png: Added.
+        * platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.txt: Added.
+        * platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.png: Added.
+        * platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.txt: Added.
+        * svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html: Added.
+        * svg/as-image/animated-svg-as-image-same-image.html: Added.
+        * svg/as-image/resources/animated-rect-same-image.svg: Copied from LayoutTests/svg/as-image/resources/animated-rect-fixed-size.svg.
+        * svg/zoom/page/zoom-coords-viewattr-01-b.svg: Add comment, why scrollbars shouldn't appear anymore here.
+
 2011-11-08  Philippe Normand  <pnormand@igalia.com>
 
         Unreviewed, skip flaky crasher on GTK.
index 76d59fc..74f1b77 100644 (file)
@@ -1486,9 +1486,6 @@ BUGWK39966 LINUX : fast/repaint/table-cell-collapsed-border.html = IMAGE
 // Thicker shadow than expected
 BUGCR23471 LEOPARD : fast/text/stroking.html = IMAGE
 
-// Failing on the bots but not locally; need investigation
-BUGCR23560 MAC : svg/as-image/animated-svg-as-image.html = PASS IMAGE
-
 // -----------------------------------------------------------------
 // END MAC PORT TESTS
 // -----------------------------------------------------------------
@@ -3849,12 +3846,8 @@ BUGWK71211 GPU LINUX DEBUG : fast/canvas/shadow-offset-3.html = PASS CRASH
 BUGWK71214 LEOPARD CPU-CG : css2.1/20110323/block-non-replaced-width-008.htm = FAIL
 BUGWK71215 SNOWLEOPARD DEBUG : animations/change-keyframes.html = TEXT
 
-BUGWK71226 : svg/as-background-image/animated-svg-as-background.html = IMAGE
-BUGWK71226 : svg/zoom/page/zoom-coords-viewattr-01-b.svg = IMAGE+TEXT
-BUGWK71226 MAC : svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html = IMAGE+TEXT
-BUGWK71226 WIN LINUX : svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html = PASS IMAGE+TEXT
-BUGWK71226 : fast/backgrounds/size/contain-and-cover-zoomed.html = IMAGE+TEXT
-BUGWK71226 : fast/backgrounds/animated-svg-as-mask.html = IMAGE+TEXT IMAGE
+BUGWK71673 MAC : svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html = IMAGE+TEXT
+BUGWK71673 WIN LINUX : svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html = PASS IMAGE+TEXT
 
 BUGWK71278 SLOW WIN RELEASE : fast/events/dispatch-message-string-data.html = PASS
 
diff --git a/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.png b/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.png
new file mode 100644 (file)
index 0000000..d99992b
Binary files /dev/null and b/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.png differ
diff --git a/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.txt b/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size-expected.txt
new file mode 100644 (file)
index 0000000..55da858
--- /dev/null
@@ -0,0 +1,11 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 371x18
+          text run at (0,0) width 371: "Images should redraw correctly when SVG animation runs"
+      RenderBlock (anonymous) at (0,34) size 784x500
+        RenderImage {IMG} at (10,10) size 480x480
+        RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.png b/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.png
new file mode 100644 (file)
index 0000000..1fa9d25
Binary files /dev/null and b/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.png differ
diff --git a/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.txt b/LayoutTests/platform/mac/svg/as-image/animated-svg-as-image-same-image-expected.txt
new file mode 100644 (file)
index 0000000..70b373a
--- /dev/null
@@ -0,0 +1,13 @@
+layer at (0,0) size 800x600
+  RenderView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (8,8) size 784x584
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 371x18
+          text run at (0,0) width 371: "Images should redraw correctly when SVG animation runs"
+      RenderBlock (anonymous) at (0,34) size 784x548
+        RenderImage {IMG} at (10,10) size 354x254 [border: (2px solid #000000)]
+        RenderBR {BR} at (374,274) size 0x0
+        RenderImage {IMG} at (10,284) size 354x254 [border: (2px solid #000000)]
+        RenderText {#text} at (0,0) size 0x0
diff --git a/LayoutTests/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html b/LayoutTests/svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html
new file mode 100644 (file)
index 0000000..af133e6
--- /dev/null
@@ -0,0 +1,27 @@
+<html>
+<head>
+  <style type="text/css" media="screen">
+    img {
+      margin: 10px;
+    }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    if (window.layoutTestController)
+      layoutTestController.waitUntilDone();
+    
+    function pageLoaded() 
+    {
+      window.setTimeout(function() {
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 400);    // empirically determined delay. SVG animation has 100ms duration.
+    }
+
+    window.addEventListener('load', pageLoaded, false);
+  </script>
+</head>
+<body>
+  <p>Images should redraw correctly when SVG animation runs</p>
+  <img src="resources/animated-rect-fixed-size.svg">
+</body>
+</html>
diff --git a/LayoutTests/svg/as-image/animated-svg-as-image-same-image.html b/LayoutTests/svg/as-image/animated-svg-as-image-same-image.html
new file mode 100644 (file)
index 0000000..874e874
--- /dev/null
@@ -0,0 +1,28 @@
+<html>
+<head>
+  <style type="text/css" media="screen">
+    img {
+      margin: 10px;
+    }
+  </style>
+  <script type="text/javascript" charset="utf-8">
+    if (window.layoutTestController)
+      layoutTestController.waitUntilDone();
+
+    function pageLoaded() 
+    {
+        window.setTimeout(function() {
+        if (window.layoutTestController)
+          layoutTestController.notifyDone();
+      }, 400);    // empirically determined delay. SVG animation has 100ms duration.
+    }
+
+    window.addEventListener('load', pageLoaded, false);
+  </script>
+</head>
+<body>
+  <p>Images should redraw correctly when SVG animation runs</p>
+  <img height="250px" width="350px" border="2" src="resources/animated-rect-same-image.svg"><br>
+  <img height="250px" width="350px" border="2" src="resources/animated-rect-same-image.svg">
+</body>
+</html>
diff --git a/LayoutTests/svg/as-image/resources/animated-rect-same-image.svg b/LayoutTests/svg/as-image/resources/animated-rect-same-image.svg
new file mode 100644 (file)
index 0000000..a1f12f2
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
+
+<!--======================================================================-->
+<!--=  Copyright 2000 World Wide Web Consortium, (Massachusetts          =-->
+<!--=  Institute of Technology, Institut National de Recherche en        =-->
+<!--=  Informatique et en Automatique, Keio University). All Rights      =-->
+<!--=  Reserved. See http://www.w3.org/Consortium/Legal/.                =-->
+<!--======================================================================-->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  id="svg-root" width="480px" height="480px" viewBox="0 0 480 360" version="1.1" baseProfile="tiny">
+   <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/">
+   </SVGTestCase>
+   <title id="test-title">animate-elem-14-t</title>
+   <desc id="test-desc">Test possible values for 'keyTimes'</desc>
+   <g id="test-body-content">
+      <g xml:space="preserve" font-family="Arial" font-size="13.5" stroke-width="3" >
+         <g transform="translate(150,140)">
+            <text font-size="36" x="-140" y="140">Time (s):</text>
+            <text font-size="36" x="290" y="140">0</text>
+            <line x1="300" y1="0" x2="300" y2="100" fill="none" stroke="#880000" />
+            <text font-size="36" x="20" y="140">6</text>
+            <line x1="30" y1="0" x2="30" y2="100" fill="none" stroke="#880000" />
+            <rect x="0" y="0" width="300" height="80" fill="#44AAFF" stroke="#880088" stroke-width="4" >
+               <animate attributeName="width" calcMode="discrete" values="300;30" keyTimes="0;.6" begin="0s" dur="100ms" fill="freeze"/>
+            </rect>
+         </g>
+      </g>
+   </g>
+   <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
+</svg>
+
index efa80b4..5bcdec9 100644 (file)
@@ -122,6 +122,7 @@ fill='none' stroke='blue'/>">
     <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
 
     <defs>
+        <!-- Note that the zooming won't have any visible effect except for stroke size changes, as width/height is 100% -->
         <script>var zoomCount = 2;</script>
         <script xlink:href="../resources/testPageZoom.js"/>
     </defs>
index cccc3d0..209b836 100644 (file)
@@ -1806,6 +1806,7 @@ IF (ENABLE_SVG)
         svg/animation/SMILTimeContainer.cpp
         svg/animation/SVGSMILElement.cpp
         svg/graphics/SVGImage.cpp
+        svg/graphics/SVGImageCache.cpp
         svg/graphics/filters/SVGFEImage.cpp
         svg/graphics/filters/SVGFilter.cpp
         svg/graphics/filters/SVGFilterBuilder.cpp
index 0266688..435c224 100644 (file)
@@ -1,3 +1,95 @@
+2011-11-08  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        Switch SVGImage cache to store ImageBuffers instead of whole SVGImages, including a DOM/Render tree
+        https://bugs.webkit.org/show_bug.cgi?id=71368
+
+        Reviewed by Antti Koivisto.
+
+        Fix regressions/races introduced by r98852. SVGImage repainting didn't work under certain circumstances.
+        The problem was hard to reproduce on Mac ports, but easily visible on Chromium, when opening two files
+        that shared the same animated SVG image. The problem of sharing a single ImageObserver across multiple
+        instances of the same SVGImage, leads to nasty problems, that are timing dependant. changedInRect() calls
+        that should only by received in one document, are received in the other as well, due the shared nature
+        of CachedImage. To avoid these problems alltogether, a new approach is needed, that was initially suggested
+        by Antti.
+
+        Avoid creating multiple SVGImages and caching them for different sizes/zoom levels. Introduce SVGImageCache
+        which holds rendered versions of the SVGImage at certain sizes/zoom levels. It holds (ImageBuffer, Image) pairs
+        for each renderer, associated with a size and zoom level.
+
+        This is a major change to the cache as introduced some weeks ago. Instead of holding multiple SVGImages, each containing
+        a whole DOM/render tree, we now create bitmap images rendered at the requested sizes/zoom levels and cache them.
+
+        Revert ImageBySizeCache changes that were needed to make it usable wih SVGImage. Its now used only in CSSImageGeneratorValue and
+        thus the extra information that CSSImageGeneratorValue doesn't need can be removed again (desired/actual size differentations, and the zoom level).
+
+        Tests: svg/as-image/animated-svg-as-image-no-fixed-intrinsic-size.html
+               svg/as-image/animated-svg-as-image-same-image.html
+
+        * CMakeLists.txt: Add svg/graphics/SVGImageCache.* to build.
+        * GNUmakefile.list.am: Ditto.
+        * Target.pri: Ditto.
+        * WebCore.gypi: Ditto.
+        * WebCore.vcproj/WebCore.vcproj: Ditto.
+        * WebCore.vcproj/copyForwardingHeaders.cmd: Copy headers from svg/graphics, as SVGImageCache is needed by CachedImage in SVG enabled builds.
+        * WebCore.xcodeproj/project.pbxproj: Add svg/graphics/SVGImageCache.* to build.
+        * css/CSSImageGeneratorValue.cpp: Remove zoom parameter from addClient/getImage, no need to pass 1 default values anymore.
+        (WebCore::CSSImageGeneratorValue::addClient):
+        (WebCore::CSSImageGeneratorValue::getImage):
+        * loader/cache/CachedImage.cpp: Stop using ImageBySizeCache, and switch to the new SVGImageCache.
+        (WebCore::CachedImage::removeClientForRenderer):
+        (WebCore::CachedImage::lookupOrCreateImageForRenderer):
+        (WebCore::CachedImage::setContainerSizeForRenderer):
+        (WebCore::CachedImage::imageSizeForRenderer):
+        (WebCore::CachedImage::clear):
+        (WebCore::CachedImage::createImage):
+        (WebCore::CachedImage::destroyDecodedData):
+        (WebCore::CachedImage::decodedSizeChanged):
+        (WebCore::CachedImage::didDraw):
+        (WebCore::CachedImage::shouldPauseAnimation):
+        (WebCore::CachedImage::animationAdvanced):
+        (WebCore::CachedImage::changedInRect):
+        * loader/cache/CachedImage.h:
+        * page/DragController.cpp: Stop using imageForRenderer(), as it may return cached BitmapImages, that don't carry a filename extension anymore, which is required here.
+        (WebCore::getImage):
+        * rendering/ImageBySizeCache.cpp: Revert changes to ImageBySizeCache, which were needed to make it usable for SVGImages. CSSImageGenerator doesn't need it.
+        (WebCore::ImageBySizeCache::addClient):
+        (WebCore::ImageBySizeCache::removeClient):
+        (WebCore::ImageBySizeCache::getImage):
+        * rendering/ImageBySizeCache.h: Ditto.
+        (WebCore::SizeAndCount::SizeAndCount):
+        * rendering/RenderImage.cpp: Stop using imageForRenderer(), use cachedImage()->image(), which is guaranteed to be a SVGImage for svg images, and not a cached bitmap copy.
+        (WebCore::RenderImage::embeddedContentBox):
+        * rendering/RenderReplaced.cpp: Simplify logic to figure out the intrinsic size - the special logic for the old SVGImage cache can go away now.
+        (WebCore::RenderReplaced::computeIntrinsicLogicalWidth):
+        (WebCore::RenderReplaced::computeIntrinsicLogicalHeight):
+        * rendering/style/StyleCachedImage.cpp: Call removeClientForRenderer(), which takes care of clearing SVGImageCache entries as well.
+        (WebCore::StyleCachedImage::removeClient): This change is needed, as we don't want to make removeClient() virtual in CachedResource.
+        * rendering/svg/RenderSVGRoot.cpp: Rename isEmbeddedThroughImageElement to isEmbeddedThroughSVGImage, as this is what it actually checks.
+        (WebCore::RenderSVGRoot::isEmbeddedThroughSVGImage):
+        * rendering/svg/RenderSVGRoot.h:
+        * svg/SVGSVGElement.cpp: Fix bug that's visible now with the SVGImageCache, which was already there before, but hard to trigger.
+        (WebCore::SVGSVGElement::currentViewBoxRect): The viewBox depends on who's asking for it: the host document or the embedded document? Take that into account.
+        * svg/SVGSVGElement.h:
+        * svg/graphics/SVGImage.cpp: Cleanup some code. Add new logic that draws a SVGImage into an ImageBuffer at a desired size & zoom.
+        (WebCore::SVGImage::setContainerSize):
+        (WebCore::SVGImage::size):
+        (WebCore::SVGImage::drawSVGToImageBuffer):
+        * svg/graphics/SVGImage.h:
+        * svg/graphics/SVGImageCache.cpp: Added. SVGImageCache caches Image/ImageBuffer pairs for each _renderer_ and size/zoom level. The ImageBySizeCache only cared about size.
+        (WebCore::SVGImageCache::SVGImageCache):
+        (WebCore::SVGImageCache::~SVGImageCache):
+        (WebCore::SVGImageCache::removeRendererFromCache):
+        (WebCore::SVGImageCache::setRequestedSizeAndZoom):
+        (WebCore::SVGImageCache::getRequestedSizeAndZoom):
+        (WebCore::SVGImageCache::imageContentChanged):
+        (WebCore::SVGImageCache::redrawTimerFired):
+        (WebCore::SVGImageCache::lookupOrCreateBitmapImageForRenderer):
+        * svg/graphics/SVGImageCache.h: Added.
+        (WebCore::SVGImageCache::create):
+        (WebCore::SVGImageCache::CachedSizeAndZoom::CachedSizeAndZoom):
+        (WebCore::SVGImageCache::CachedImageData::CachedImageData):
+
 2011-11-07  Yury Semikhatsky  <yurys@chromium.org>
 
         Web Inspector: refactor shortcuts and settings screens
index ca52521..bbbb85d 100644 (file)
@@ -3536,6 +3536,8 @@ webcore_sources += \
        Source/WebCore/svg/graphics/filters/SVGFilterBuilder.h \
        Source/WebCore/svg/graphics/filters/SVGFilter.cpp \
        Source/WebCore/svg/graphics/filters/SVGFilter.h \
+       Source/WebCore/svg/graphics/SVGImageCache.cpp \
+       Source/WebCore/svg/graphics/SVGImageCache.h \
        Source/WebCore/svg/graphics/SVGImage.cpp \
        Source/WebCore/svg/graphics/SVGImage.h \
        Source/WebCore/svg/LinearGradientAttributes.h \
index f0f11c8..898e3bc 100644 (file)
@@ -2483,6 +2483,7 @@ HEADERS += \
     svg/graphics/filters/SVGFilterBuilder.h \
     svg/graphics/filters/SVGFilter.h \
     svg/graphics/SVGImage.h \
+    svg/graphics/SVGImageCache.h \
     svg/properties/SVGAttributeToPropertyMap.h \
     svg/properties/SVGAnimatedEnumerationPropertyTearOff.h \
     svg/properties/SVGAnimatedListPropertyTearOff.h \
@@ -3316,6 +3317,7 @@ contains(DEFINES, ENABLE_SVG=1) {
         svg/graphics/filters/SVGFilter.cpp \
         svg/graphics/filters/SVGFilterBuilder.cpp \
         svg/graphics/SVGImage.cpp \
+        svg/graphics/SVGImageCache.cpp \
         svg/properties/SVGAttributeToPropertyMap.cpp \
         svg/properties/SVGPathSegListPropertyTearOff.cpp
 
index a9b160c..d588cc1 100644 (file)
             'svg/animation/SMILTimeContainer.cpp',
             'svg/animation/SMILTimeContainer.h',
             'svg/animation/SVGSMILElement.cpp',
+            'svg/graphics/SVGImageCache.cpp',
+            'svg/graphics/SVGImageCache.h',
             'svg/graphics/SVGImage.cpp',
             'svg/graphics/SVGImage.h',
             'svg/graphics/filters/SVGFEImage.cpp',
index 1b75e50..356b020 100755 (executable)
                                Name="graphics"
                                >
                                <File
+                                       RelativePath="..\svg\graphics\SVGImageCache.cpp"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath="..\svg\graphics\SVGImageCache.h"
+                                       >
+                               </File>
+                               <File
                                        RelativePath="..\svg\graphics\SVGImage.cpp"
                                        >
                                </File>
index 224ce03..92a6e30 100755 (executable)
@@ -70,6 +70,7 @@ xcopy /y /d "%ProjectDir%..\dom\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
 xcopy /y /d "%ProjectDir%..\xml\parser\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
 xcopy /y /d "%ProjectDir%..\xml\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
 xcopy /y /d "%ProjectDir%..\svg\animation\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
+xcopy /y /d "%ProjectDir%..\svg\graphics\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
 xcopy /y /d "%ProjectDir%..\svg\properties\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
 xcopy /y /d "%ProjectDir%..\svg\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
 xcopy /y /d "%ProjectDir%..\storage\*.h" "%CONFIGURATIONBUILDDIR%\include\WebCore"
index a6a5b30..bb2a4c2 100644 (file)
                08F0BFC61255C53C00075185 /* SVGTextMetrics.h in Headers */ = {isa = PBXBuildFile; fileRef = 08F0BFC11255C53C00075185 /* SVGTextMetrics.h */; };
                08F2F0091213E61700DCEC48 /* RenderImageResource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08F2F0071213E61700DCEC48 /* RenderImageResource.cpp */; };
                08F2F00A1213E61700DCEC48 /* RenderImageResource.h in Headers */ = {isa = PBXBuildFile; fileRef = 08F2F0081213E61700DCEC48 /* RenderImageResource.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               08F859D41463F9CD0067D933 /* SVGImageCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08F859D21463F9CD0067D933 /* SVGImageCache.cpp */; };
+               08F859D51463F9CD0067D933 /* SVGImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 08F859D31463F9CD0067D933 /* SVGImageCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
                08FB17C113BC7E9100040086 /* SVGAttributeToPropertyMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08FB17C013BC7E9100040086 /* SVGAttributeToPropertyMap.cpp */; };
                08FB3F8413BC754C0099FC18 /* SVGAttributeToPropertyMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 08FB3F8313BC754C0099FC18 /* SVGAttributeToPropertyMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
                08FE0BC5127E2AC1000C4FB5 /* SVGAnimatedPreserveAspectRatio.h in Headers */ = {isa = PBXBuildFile; fileRef = 08FE0BC4127E2AC1000C4FB5 /* SVGAnimatedPreserveAspectRatio.h */; settings = {ATTRIBUTES = (Private, ); }; };
                08F0BFC11255C53C00075185 /* SVGTextMetrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGTextMetrics.h; sourceTree = "<group>"; };
                08F2F0071213E61700DCEC48 /* RenderImageResource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderImageResource.cpp; sourceTree = "<group>"; };
                08F2F0081213E61700DCEC48 /* RenderImageResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderImageResource.h; sourceTree = "<group>"; };
+               08F859D21463F9CD0067D933 /* SVGImageCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGImageCache.cpp; sourceTree = "<group>"; };
+               08F859D31463F9CD0067D933 /* SVGImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGImageCache.h; sourceTree = "<group>"; };
                08FB17C013BC7E9100040086 /* SVGAttributeToPropertyMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAttributeToPropertyMap.cpp; sourceTree = "<group>"; };
                08FB3F8313BC754C0099FC18 /* SVGAttributeToPropertyMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAttributeToPropertyMap.h; sourceTree = "<group>"; };
                08FE0BC4127E2AC1000C4FB5 /* SVGAnimatedPreserveAspectRatio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimatedPreserveAspectRatio.h; sourceTree = "<group>"; };
                                B255989C0D00D8B800BB825C /* filters */,
                                B255990B0D00D8B900BB825C /* SVGImage.cpp */,
                                B255990C0D00D8B900BB825C /* SVGImage.h */,
+                               08F859D21463F9CD0067D933 /* SVGImageCache.cpp */,
+                               08F859D31463F9CD0067D933 /* SVGImageCache.h */,
                        );
                        path = graphics;
                        sourceTree = "<group>";
                                07846343145B151A00A58DF1 /* JSTrackEvent.h in Headers */,
                                07846385145B1B8E00A58DF1 /* JSTrackCustom.h in Headers */,
                                2D8FEBDD143E3EF70072502B /* CSSCrossfadeValue.h in Headers */,
+                               08F859D51463F9CD0067D933 /* SVGImageCache.h in Headers */,
                                3169379C14609C6C00C01362 /* DragSession.h in Headers */,
                                CAE9F910146441F000C245B0 /* CSSAspectRatioValue.h in Headers */,
                                976F36EB14686225005E93B4 /* SecurityContext.h in Headers */,
                                07846342145B151A00A58DF1 /* JSTrackEvent.cpp in Sources */,
                                07689D6E145B52CC001CD132 /* JSTrackEventCustom.cpp in Sources */,
                                2D8FEBDC143E3EF70072502B /* CSSCrossfadeValue.cpp in Sources */,
+                               08F859D41463F9CD0067D933 /* SVGImageCache.cpp in Sources */,
                                CAE9F90F146441F000C245B0 /* CSSAspectRatioValue.cpp in Sources */,
                                CDEA763014608A53008B31F1 /* PlatformClockCA.cpp in Sources */,
                                CDEA76341460B56F008B31F1 /* ClockGeneric.cpp in Sources */,
index 258ef0e..28486c0 100644 (file)
@@ -48,7 +48,7 @@ CSSImageGeneratorValue::~CSSImageGeneratorValue()
 void CSSImageGeneratorValue::addClient(RenderObject* renderer, const IntSize& size)
 {
     ref();
-    m_imageCache.addClient(renderer, size, 1);
+    m_imageCache.addClient(renderer, size);
 }
 
 void CSSImageGeneratorValue::removeClient(RenderObject* renderer)
@@ -61,7 +61,7 @@ Image* CSSImageGeneratorValue::getImage(RenderObject* renderer, const IntSize& s
 {
     // If renderer is the only client, make sure we don't delete this, if the size changes (as this will result in addClient/removeClient calls).
     RefPtr<CSSImageGeneratorValue> protect(this);
-    return m_imageCache.getImage(renderer, size, 1);
+    return m_imageCache.getImage(renderer, size);
 }
 
 void CSSImageGeneratorValue::putImage(const IntSize& size, PassRefPtr<Image> image)
index 0cc2d8a..1c45895 100644 (file)
@@ -90,6 +90,15 @@ void CachedImage::load(CachedResourceLoader* cachedResourceLoader, const Resourc
         setLoading(false);
 }
 
+void CachedImage::removeClientForRenderer(RenderObject* renderer)
+{
+#if ENABLE(SVG)
+    if (m_svgImageCache)
+        m_svgImageCache->removeRendererFromCache(renderer);
+#endif
+    removeClient(renderer);
+}
+
 void CachedImage::didAddClient(CachedResourceClient* c)
 {
     if (m_decodedDataDeletionTimer.isActive())
@@ -132,48 +141,18 @@ bool CachedImage::willPaintBrokenImage() const
 }
 
 #if ENABLE(SVG)
-inline Image* CachedImage::lookupImageForSize(const IntSize& size) const
-{
-    if (!m_image)
-        return 0;
-    if (!m_image->isSVGImage())
-        return m_image.get();
-    if (Image* image = m_svgImageCache.imageForSize(size))
-        return image;
-    return m_image.get();
-}
-
 inline Image* CachedImage::lookupOrCreateImageForRenderer(const RenderObject* renderer)
 {
     if (!m_image)
         return 0;
     if (!m_image->isSVGImage())
         return m_image.get();
-
-    // Request requested size/zoom for this renderer from the cache.
-    IntSize size;
-    float zoom = 1;
-    m_svgImageCache.getRequestedSizeAndZoom(renderer, size, zoom);
-    if (size.isEmpty())
+    Image* useImage = m_svgImageCache->lookupOrCreateBitmapImageForRenderer(renderer);
+    if (useImage == Image::nullImage())
         return m_image.get();
-
-    if (Image* image = m_svgImageCache.getImage(renderer, size, zoom))
-        return image;
-
-    // Create and cache new image at requested size.
-    RefPtr<Image> newImage = SVGImage::createWithDataAndSize(this, m_data.get(), size, zoom);
-    Image* newImagePtr = newImage.get();
-    m_svgImageCache.addClient(renderer, size, zoom);
-    m_svgImageCache.putImage(size, newImage.release());
-    return newImagePtr;
+    return useImage;
 }
-
 #else
-inline Image* CachedImage::lookupImageForSize(const IntSize&) const
-{
-    return m_image.get();
-}
-
 inline Image* CachedImage::lookupOrCreateImageForRenderer(const RenderObject*)
 {
     return m_image.get();
@@ -223,7 +202,7 @@ void CachedImage::setContainerSizeForRenderer(const RenderObject* renderer, cons
         m_image->setContainerSize(containerSize);
         return;
     }
-    m_svgImageCache.addClient(renderer, containerSize, containerZoom);
+    m_svgImageCache->setRequestedSizeAndZoom(renderer, SVGImageCache::SizeAndZoom(containerSize, containerZoom));
 #else
     UNUSED_PARAM(renderer);
     m_image->setContainerSize(containerSize);
@@ -263,12 +242,18 @@ IntSize CachedImage::imageSizeForRenderer(const RenderObject* renderer, float mu
 #if ENABLE(SVG)
     if (m_image->isSVGImage()) {
         // SVGImages already includes the zooming in its intrinsic size.
-        IntSize size;
-        float zoom = 1;
-        m_svgImageCache.getRequestedSizeAndZoom(renderer, size, zoom);
-        if (!size.isEmpty())
-            return size;
-        return m_image->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;
+        }
+        return sizeAndZoom.size;
     }
 #endif
 
@@ -312,7 +297,9 @@ void CachedImage::checkShouldPaintBrokenImage()
 void CachedImage::clear()
 {
     destroyDecodedData();
+#if ENABLE(SVG)
     m_svgImageCache.clear();
+#endif
     m_image = 0;
     setEncodedSize(0);
 }
@@ -330,7 +317,9 @@ inline void CachedImage::createImage()
 #endif
 #if ENABLE(SVG)
     if (m_response.mimeType() == "image/svg+xml") {
-        m_image = SVGImage::create(this);
+        RefPtr<SVGImage> svgImage = SVGImage::create(this);
+        m_svgImageCache = SVGImageCache::create(svgImage.get());
+        m_image = svgImage.release();
         return;
     }
 #endif
@@ -410,16 +399,13 @@ void CachedImage::destroyDecodedData()
         setDecodedSize(0);
         if (!MemoryCache::shouldMakeResourcePurgeableOnEviction())
             makePurgeable(true);
-    } else if (m_image && !errorOccurred() && !m_image->isSVGImage())
+    } else if (m_image && !errorOccurred())
         m_image->destroyDecodedData();
 }
 
 void CachedImage::decodedSizeChanged(const Image* image, int delta)
 {
-    if (!image)
-        return;
-    Image* useImage = lookupImageForSize(image->size());
-    if (image != useImage)
+    if (!image || image != m_image)
         return;
     
     setDecodedSize(decodedSize() + delta);
@@ -427,10 +413,7 @@ void CachedImage::decodedSizeChanged(const Image* image, int delta)
 
 void CachedImage::didDraw(const Image* image)
 {
-    if (!image)
-        return;
-    Image* useImage = lookupImageForSize(image->size());
-    if (image != useImage)
+    if (!image || image != m_image)
         return;
     
     double timeStamp = FrameView::currentPaintTimeStamp();
@@ -442,10 +425,7 @@ void CachedImage::didDraw(const Image* image)
 
 bool CachedImage::shouldPauseAnimation(const Image* image)
 {
-    if (!image)
-        return false;
-    Image* useImage = lookupImageForSize(image->size());
-    if (image != useImage)
+    if (!image || image != m_image)
         return false;
     
     CachedResourceClientWalker<CachedImageClient> w(m_clients);
@@ -459,22 +439,23 @@ bool CachedImage::shouldPauseAnimation(const Image* image)
 
 void CachedImage::animationAdvanced(const Image* image)
 {
-    if (!image)
-        return;
-    Image* useImage = lookupImageForSize(image->size());
-    if (image != useImage)
+    if (!image || image != m_image)
         return;
     notifyObservers();
 }
 
 void CachedImage::changedInRect(const Image* image, const IntRect& rect)
 {
-    if (!image)
+    if (!image || image != m_image)
         return;
-    Image* useImage = lookupImageForSize(image->size());
-    if (image != useImage)
+#if ENABLE(SVG)
+    // We have to update the cached ImageBuffers if the underlying content changed.
+    if (image->isSVGImage()) {
+        m_svgImageCache->imageContentChanged();
         return;
+    }
+#endif
     notifyObservers(&rect);
 }
 
-} //namespace WebCore
+} // namespace WebCore
index 7cba852..bc1bfb1 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "CachedResource.h"
 #include "CachedResourceClient.h"
-#include "ImageBySizeCache.h"
+#include "SVGImageCache.h"
 #include "ImageObserver.h"
 #include "IntRect.h"
 #include "Timer.h"
@@ -67,6 +67,7 @@ public:
     IntSize imageSizeForRenderer(const RenderObject*, float multiplier); // returns the size of the complete image.
     void computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio);
 
+    void removeClientForRenderer(RenderObject*);
     virtual void didAddClient(CachedResourceClient*);
     
     virtual void allClientsRemoved();
@@ -94,7 +95,6 @@ public:
     virtual void changedInRect(const Image*, const IntRect&);
 
 private:
-    Image* lookupImageForSize(const IntSize&) const;
     Image* lookupOrCreateImageForRenderer(const RenderObject*);
 
     void createImage();
@@ -106,7 +106,9 @@ private:
     void checkShouldPaintBrokenImage();
 
     RefPtr<Image> m_image;
-    mutable ImageBySizeCache m_svgImageCache;
+#if ENABLE(SVG)
+    OwnPtr<SVGImageCache> m_svgImageCache;
+#endif
     Timer<CachedImage> m_decodedDataDeletionTimer;
     bool m_shouldPaintBrokenImage;
 };
index 4d5311a..dc6c726 100644 (file)
@@ -653,8 +653,11 @@ static Image* getImage(Element* element)
 {
     ASSERT(element);
     CachedImage* cachedImage = getCachedImage(element);
+    // Don't use cachedImage->imageForRenderer() here as that may return BitmapImages for cached SVG Images.
+    // Users of getImage() want access to the SVGImage, in order to figure out the filename extensions,
+    // which would be empty when asking the cached BitmapImages.
     return (cachedImage && !cachedImage->errorOccurred()) ?
-        cachedImage->imageForRenderer(element->renderer()) : 0;
+        cachedImage->image() : 0;
 }
 
 static void prepareClipboardForImageDrag(Frame* source, Clipboard* clipboard, Element* node, const KURL& linkURL, const KURL& imageURL, const String& label)
index d396610..615cb6d 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "Image.h"
 #include "IntSize.h"
-#include "IntSizeHash.h"
 #include "RenderObject.h"
 
 namespace WebCore {
@@ -32,7 +31,7 @@ ImageBySizeCache::ImageBySizeCache()
 {
 }
 
-void ImageBySizeCache::addClient(const RenderObject* renderer, const IntSize& size, float zoom)
+void ImageBySizeCache::addClient(const RenderObject* renderer, const IntSize& size)
 {
     ASSERT(renderer);
     if (!size.isEmpty())
@@ -40,11 +39,9 @@ void ImageBySizeCache::addClient(const RenderObject* renderer, const IntSize& si
     
     RenderObjectSizeCountMap::iterator it = m_clients.find(renderer);
     if (it == m_clients.end())
-        m_clients.add(renderer, SizeZoomAndCount(size, zoom, 1));
+        m_clients.add(renderer, SizeAndCount(size, 1));
     else {
-        SizeZoomAndCount& sizeCount = it->second;
-        sizeCount.requestedSize = size;
-        sizeCount.requestedZoom = zoom;
+        SizeAndCount& sizeCount = it->second;
         ++sizeCount.count;
     }
 }
@@ -55,8 +52,9 @@ void ImageBySizeCache::removeClient(const RenderObject* renderer)
     RenderObjectSizeCountMap::iterator it = m_clients.find(renderer);
     ASSERT(it != m_clients.end());
 
-    SizeZoomAndCount& sizeCount = it->second;
-    IntSize size = sizeCount.actualSize;
+    IntSize removedImageSize;
+    SizeAndCount& sizeCount = it->second;
+    IntSize size = sizeCount.size;
     if (!size.isEmpty()) {
         m_sizes.remove(size);
         if (!m_sizes.contains(size))
@@ -67,15 +65,15 @@ void ImageBySizeCache::removeClient(const RenderObject* renderer)
         m_clients.remove(renderer);
 }
 
-Image* ImageBySizeCache::getImage(const RenderObject* renderer, const IntSize& size, float zoom)
+Image* ImageBySizeCache::getImage(const RenderObject* renderer, const IntSize& size)
 {
     RenderObjectSizeCountMap::iterator it = m_clients.find(renderer);
     if (it != m_clients.end()) {
-        SizeZoomAndCount& sizeCount = it->second;
-        IntSize oldSize = sizeCount.actualSize;
+        SizeAndCount& sizeCount = it->second;
+        IntSize oldSize = sizeCount.size;
         if (oldSize != size) {
             removeClient(renderer);
-            addClient(renderer, size, zoom);
+            addClient(renderer, size);
         }
     }
 
@@ -87,46 +85,9 @@ Image* ImageBySizeCache::getImage(const RenderObject* renderer, const IntSize& s
     return m_images.get(size).get();
 }
 
-void ImageBySizeCache::getRequestedSizeAndZoom(const RenderObject* renderer, IntSize& size, float& zoom)
-{
-    RenderObjectSizeCountMap::iterator it = m_clients.find(renderer);
-    if (it == m_clients.end())
-        return;
-    SizeZoomAndCount& sizeCount = it->second;
-    size = sizeCount.requestedSize;
-    zoom = sizeCount.requestedZoom;
-}
-
 void ImageBySizeCache::putImage(const IntSize& size, PassRefPtr<Image> image)
 {
     m_images.add(size, image);
 }
 
-void ImageBySizeCache::clear()
-{
-    m_sizes.clear();
-    m_clients.clear();
-    m_images.clear();
-}
-
-Image* ImageBySizeCache::imageForSize(const IntSize& size) const
-{
-    if (size.isEmpty())
-        return 0;
-    HashMap<IntSize, RefPtr<Image> >::const_iterator it = m_images.find(size);
-    if (it == m_images.end())
-        return 0;
-    return it->second.get();
-}
-
-Image* ImageBySizeCache::imageForRenderer(const RenderObject* renderer) const
-{
-    if (!renderer)
-        return 0;
-    RenderObjectSizeCountMap::const_iterator it = m_clients.find(renderer);
-    if (it == m_clients.end())
-        return 0;
-    return imageForSize(it->second.actualSize);
-}
-
 } // namespace WebCore
index 0b19864..f5c5535 100644 (file)
@@ -31,41 +31,29 @@ namespace WebCore {
 class Image;
 class RenderObject;
 
-struct SizeZoomAndCount {
-    SizeZoomAndCount(IntSize newSize = IntSize(), float newZoom = 0, int newCount = 0)
-        : actualSize(newSize)
-        , requestedSize(newSize)
-        , actualZoom(newZoom)
-        , requestedZoom(newZoom)
+struct SizeAndCount {
+    SizeAndCount(IntSize newSize = IntSize(), int newCount = 0)
+        : size(newSize)
         , count(newCount)
     {
     }
 
-    IntSize actualSize;
-    IntSize requestedSize;
-    float actualZoom;
-    float requestedZoom;
+    IntSize size;
     int count;
 };
 
-typedef HashMap<const RenderObject*, SizeZoomAndCount> RenderObjectSizeCountMap;
+typedef HashMap<const RenderObject*, SizeAndCount> RenderObjectSizeCountMap;
 
 class ImageBySizeCache {
 public:
     ImageBySizeCache();
 
-    void addClient(const RenderObject*, const IntSize&, float zoom);
+    void addClient(const RenderObject*, const IntSize&);
     void removeClient(const RenderObject*);
 
-    Image* getImage(const RenderObject*, const IntSize&, float zoom);
-    void getRequestedSizeAndZoom(const RenderObject*, IntSize&, float& zoom);
-
+    Image* getImage(const RenderObject*, const IntSize&);
     void putImage(const IntSize&, PassRefPtr<Image>);
 
-    void clear();
-
-    Image* imageForSize(const IntSize&) const;
-    Image* imageForRenderer(const RenderObject*) const;
     const RenderObjectSizeCountMap& clients() const { return m_clients; }
 
 private:
index 3319787..0a70781 100644 (file)
@@ -545,9 +545,9 @@ RenderBox* RenderImage::embeddedContentBox() const
         return 0;
 
 #if ENABLE(SVG)
-    RefPtr<Image> image = m_imageResource->image();
-    if (image && image->isSVGImage())
-        return static_pointer_cast<SVGImage>(image)->embeddedContentBox();
+    CachedImage* cachedImage = m_imageResource->cachedImage();
+    if (cachedImage && cachedImage->image() && cachedImage->image()->isSVGImage())
+        return static_cast<SVGImage*>(cachedImage->image())->embeddedContentBox();
 #endif
 
     return 0;
index c718c39..f2ecfba 100644 (file)
@@ -200,10 +200,8 @@ bool RenderReplaced::shouldPaint(PaintInfo& paintInfo, const LayoutPoint& paintO
 
 int RenderReplaced::computeIntrinsicLogicalWidth(RenderBox* contentRenderer, bool includeMaxWidth) const
 {
-    if (m_hasIntrinsicSize) {
-        if (!contentRenderer || !contentRenderer->style()->logicalWidth().isFixed())
-            return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth);
-    }
+    if (m_hasIntrinsicSize)
+        return computeReplacedLogicalWidthRespectingMinMaxWidth(calcAspectRatioLogicalWidth(), includeMaxWidth);
     ASSERT(contentRenderer);
     ASSERT(contentRenderer->style());
     return contentRenderer->computeReplacedLogicalWidthRespectingMinMaxWidth(contentRenderer->computeReplacedLogicalWidthUsing(contentRenderer->style()->logicalWidth()), includeMaxWidth);
@@ -211,10 +209,8 @@ int RenderReplaced::computeIntrinsicLogicalWidth(RenderBox* contentRenderer, boo
 
 int RenderReplaced::computeIntrinsicLogicalHeight(RenderBox* contentRenderer) const
 {
-    if (m_hasIntrinsicSize) {
-        if (!contentRenderer || !contentRenderer->style()->logicalHeight().isFixed())
-            return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight());
-    }
+    if (m_hasIntrinsicSize)
+        return computeReplacedLogicalHeightRespectingMinMaxHeight(calcAspectRatioLogicalHeight());
     ASSERT(contentRenderer);
     ASSERT(contentRenderer->style());
     return contentRenderer->computeReplacedLogicalHeightRespectingMinMaxHeight(contentRenderer->computeReplacedLogicalHeightUsing(contentRenderer->style()->logicalHeight()));
index 4078c49..1a7d9ef 100644 (file)
@@ -86,7 +86,7 @@ void StyleCachedImage::addClient(RenderObject* renderer)
 
 void StyleCachedImage::removeClient(RenderObject* renderer)
 {
-    m_image->removeClient(renderer);
+    m_image->removeClientForRenderer(renderer);
 }
 
 PassRefPtr<Image> StyleCachedImage::image(RenderObject* renderer, const IntSize&) const
index 9b6b88d..1195af4 100644 (file)
@@ -117,7 +117,7 @@ void RenderSVGRoot::computePreferredLogicalWidths()
     setPreferredLogicalWidthsDirty(false);
 }
 
-bool RenderSVGRoot::isEmbeddedThroughImageElement() const
+bool RenderSVGRoot::isEmbeddedThroughSVGImage() const
 {
     if (!node())
         return false;
index c0335f6..2e41354 100644 (file)
@@ -39,7 +39,7 @@ public:
     explicit RenderSVGRoot(SVGStyledElement*);
     virtual ~RenderSVGRoot();
 
-    bool isEmbeddedThroughImageElement() const;
+    bool isEmbeddedThroughSVGImage() const;
 
     virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicRatio, bool& isPercentageIntrinsicSize) const;
     const RenderObjectChildList* children() const { return &m_children; }
index efb2b2b..dfce6cd 100644 (file)
@@ -551,23 +551,33 @@ bool SVGSVGElement::isOutermostSVG() const
     return !parentNode()->isSVGElement();
 }
 
-FloatRect SVGSVGElement::currentViewBoxRect() const
+FloatRect SVGSVGElement::currentViewBoxRect(CalculateViewBoxMode mode) const
 {
+    // FIXME: The interaction of 'currentView' and embedding SVGs in other documents, is untested and unspecified.
     if (useCurrentView()) {
         if (SVGViewSpec* view = currentView()) // what if we should use it but it is not set?
             return view->viewBox();
         return FloatRect();
     }
 
-    // Synthesize a viewBox if we're embedded through a <img> element, if none is present.
+    bool isEmbeddedThroughSVGImage = renderer() && renderer()->isSVGRoot() ? toRenderSVGRoot(renderer())->isEmbeddedThroughSVGImage() : false;
+    bool hasFixedSize = width().unitType() != LengthTypePercentage && height().unitType() != LengthTypePercentage;
+
     FloatRect useViewBox = viewBox();
-    if (useViewBox.isEmpty() && width().unitType() != LengthTypePercentage && height().unitType() != LengthTypePercentage) {
-        if (RenderObject* renderer = this->renderer()) {
-            if (renderer->isSVGRoot() && toRenderSVGRoot(renderer)->isEmbeddedThroughImageElement())
-                useViewBox = FloatRect(0, 0, width().value(this), height().value(this));
-        }
+    if (useViewBox.isEmpty()) {
+        // If no viewBox is specified but non-relative width/height values, then we
+        // should always synthesize a viewBox if we're embedded through a SVGImage.
+        if (hasFixedSize && isEmbeddedThroughSVGImage)
+            return FloatRect(0, 0, width().value(this), height().value(this));
+        return FloatRect();
     }
 
+    // If a viewBox is specified and non-relative width/height values, then the host document only
+    // uses the width/height values to figure out the intrinsic size when embedding us, whereas the
+    // embedded document sees specified viewBox only.
+    if (hasFixedSize && mode == CalculateViewBoxInHostDocument)
+        return FloatRect(0, 0, width().value(this), height().value(this));
+
     return useViewBox;
 }
 
index bc43a2d..f6170ac 100644 (file)
@@ -72,8 +72,13 @@ public:
     void setUseCurrentView(bool currentView);
 
     SVGViewSpec* currentView() const;
-    FloatRect currentViewBoxRect() const;
 
+    enum CalculateViewBoxMode {
+        CalculateViewBoxInHostDocument,
+        CalculateViewBoxInCurrentDocument
+    };
+
+    FloatRect currentViewBoxRect(CalculateViewBoxMode = CalculateViewBoxInCurrentDocument) const;
     float currentScale() const;
     void setCurrentScale(float scale);
 
index 0a333af..9466a66 100644 (file)
@@ -102,43 +102,9 @@ SVGImage::~SVGImage()
     ASSERT(!m_chromeClient || !m_chromeClient->image());
 }
 
-PassRefPtr<SVGImage> SVGImage::createWithDataAndSize(ImageObserver* observer, SharedBuffer* data, const IntSize& size, float zoom)
+void SVGImage::setContainerSize(const IntSize&)
 {
-    ASSERT(!size.isEmpty());
-
-    RefPtr<SVGImage> image = adoptRef(new SVGImage(0));
-    image->setData(data, true);
-    image->setContainerSize(size);
-    image->setContainerZoom(zoom);
-    image->setImageObserver(observer);
-    return image.release();
-}
-
-void SVGImage::setContainerZoom(float containerZoom)
-{
-    if (!m_page)
-        return;
-    Frame* frame = m_page->mainFrame();
-    frame->setPageZoomFactor(containerZoom);
-}
-
-void SVGImage::setContainerSize(const IntSize& containerSize)
-{
-    ASSERT(!containerSize.isEmpty());
-    ASSERT(!imageObserver());
-    
-    if (!m_page)
-        return;
-    Frame* frame = m_page->mainFrame();
-    SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement();
-    if (!rootElement)
-        return;
-
-    RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
-    if (!renderer)
-        return;
-    renderer->setContainerSize(containerSize);
-    frame->view()->resize(size());
+    ASSERT_NOT_REACHED();
 }
 
 bool SVGImage::usesContainerSize() const
@@ -174,7 +140,7 @@ IntSize SVGImage::size() const
 
     // Assure that a container size is always given for a non-identity zoom level.
     ASSERT(renderer->style()->effectiveZoom() == 1);
-    IntSize size = enclosingIntRect(rootElement->currentViewBoxRect()).size();
+    IntSize size = enclosingIntRect(rootElement->currentViewBoxRect(SVGSVGElement::CalculateViewBoxInHostDocument)).size();
     if (!size.isEmpty())
         return size;
 
@@ -182,6 +148,56 @@ IntSize SVGImage::size() const
     return IntSize(300, 150);
 }
 
+void SVGImage::drawSVGToImageBuffer(ImageBuffer* buffer, const IntSize& size, float zoom, ShouldClearBuffer shouldClear)
+{
+    // FIXME: This doesn't work correctly with animations. If an image contains animations, that say run for 2 seconds,
+    // and we currently have one <img> that displays us. If we open another document referencing the same SVGImage it
+    // will display the document at a time where animations already ran - even though it has its own ImageBuffer.
+    // We currently don't implement SVGSVGElement::setCurrentTime, and can NOT go back in time, once animations started.
+    // There's no way to fix this besides avoiding style/attribute mutations from SVGAnimationElement.
+    ASSERT(buffer);
+    ASSERT(!size.isEmpty());
+
+    Frame* frame = m_page->mainFrame();
+    SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement();
+    if (!rootElement)
+        return;
+    RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer());
+    if (!renderer)
+        return;
+
+    // Draw image at requested size.
+    ImageObserver* observer = imageObserver();
+    ASSERT(observer);
+
+    // Temporarily reset image observer, we don't want to receive any changeInRect() calls due this relayout.
+    setImageObserver(0);
+    renderer->setContainerSize(size);
+    frame->view()->resize(this->size());
+    if (zoom != 1)
+        frame->setPageZoomFactor(zoom);
+
+    // Eventually clear image buffer.
+    IntRect rect(IntPoint(), size);
+    if (shouldClear == ClearImageBuffer)
+        buffer->context()->clearRect(rect);
+
+    // Draw SVG on top of ImageBuffer.
+    draw(buffer->context(), rect, rect, ColorSpaceDeviceRGB, CompositeSourceOver);
+
+    // Reset container size & zoom to initial state. Otherwhise the size() of this
+    // image would return whatever last size was set by drawSVGToImageBuffer().
+    if (zoom != 1)
+        frame->setPageZoomFactor(1);
+
+    renderer->setContainerSize(IntSize());
+    frame->view()->resize(this->size());
+    if (frame->view()->needsLayout())
+        frame->view()->layout();
+
+    setImageObserver(observer); 
+}
+
 void SVGImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp)
 {
     if (!m_page)
index 638491e..1e3fe4f 100644 (file)
@@ -34,6 +34,7 @@
 
 namespace WebCore {
 
+class ImageBuffer;
 class Page;
 class RenderBox;
 class SVGImageChromeClient;
@@ -45,12 +46,16 @@ public:
         return adoptRef(new SVGImage(observer));
     }
 
-    static PassRefPtr<SVGImage> createWithDataAndSize(ImageObserver*, SharedBuffer*, const IntSize&, float zoom);
+    enum ShouldClearBuffer {
+        ClearImageBuffer,
+        DontClearImageBuffer
+    };
 
-    void setContainerZoom(float);
+    void drawSVGToImageBuffer(ImageBuffer*, const IntSize&, float zoom, ShouldClearBuffer);
     RenderBox* embeddedContentBox() const;
 
     virtual bool isSVGImage() const { return true; }
+    virtual IntSize size() const;
 
 private:
     virtual ~SVGImage();
@@ -61,8 +66,6 @@ private:
     virtual bool usesContainerSize() const;
     virtual void computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio);
 
-    virtual IntSize size() const;
-
     virtual bool dataChanged(bool allDataReceived);
 
     // FIXME: SVGImages are underreporting decoded sizes and will be unable
diff --git a/Source/WebCore/svg/graphics/SVGImageCache.cpp b/Source/WebCore/svg/graphics/SVGImageCache.cpp
new file mode 100644 (file)
index 0000000..cd901f4
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 Research In Motion Limited. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "SVGImageCache.h"
+
+#if ENABLE(SVG)
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "RenderSVGRoot.h"
+#include "SVGImage.h"
+
+namespace WebCore {
+
+SVGImageCache::SVGImageCache(SVGImage* svgImage)
+    : m_svgImage(svgImage)
+    , m_redrawTimer(this, &SVGImageCache::redrawTimerFired)
+{
+    ASSERT(m_svgImage);
+}
+
+SVGImageCache::~SVGImageCache()
+{
+    m_sizeAndZoomMap.clear();
+
+    ImageDataMap::iterator end = m_imageDataMap.end();
+    for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it)
+        delete it->second.buffer;
+
+    m_imageDataMap.clear();
+}
+
+void SVGImageCache::removeRendererFromCache(const RenderObject* renderer)
+{
+    ASSERT(renderer);
+    m_sizeAndZoomMap.remove(renderer);
+
+    ImageDataMap::iterator it = m_imageDataMap.find(renderer);
+    if (it == m_imageDataMap.end())
+        return;
+
+    delete it->second.buffer;
+    m_imageDataMap.remove(it);
+}
+
+void SVGImageCache::setRequestedSizeAndZoom(const RenderObject* renderer, const SizeAndZoom& sizeAndZoom)
+{
+    ASSERT(renderer);
+    ASSERT(!sizeAndZoom.size.isEmpty());
+    m_sizeAndZoomMap.set(renderer, sizeAndZoom);
+}
+
+SVGImageCache::SizeAndZoom SVGImageCache::requestedSizeAndZoom(const RenderObject* renderer) const
+{
+    ASSERT(renderer);
+    SizeAndZoomMap::const_iterator it = m_sizeAndZoomMap.find(renderer);
+    if (it == m_sizeAndZoomMap.end())
+        return SizeAndZoom();
+    return it->second;
+}
+
+void SVGImageCache::imageContentChanged()
+{
+    ImageDataMap::iterator end = m_imageDataMap.end();
+    for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it)
+        it->second.imageNeedsUpdate = true;
+
+    // Start redrawing dirty images with a timer, as imageContentChanged() may be called
+    // by the FrameView of the SVGImage which is currently in FrameView::layout().
+    if (!m_redrawTimer.isActive())
+        m_redrawTimer.startOneShot(0);
+}
+
+void SVGImageCache::redrawTimerFired(Timer<SVGImageCache>*)
+{
+    ImageDataMap::iterator end = m_imageDataMap.end();
+    for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it) {
+        ImageData& data = it->second;
+        if (!data.imageNeedsUpdate)
+            continue;
+        // If the content changed we redraw using our existing ImageBuffer.
+        ASSERT(data.buffer);
+        ASSERT(data.image);
+        m_svgImage->drawSVGToImageBuffer(data.buffer, data.sizeAndZoom.size, data.sizeAndZoom.zoom, SVGImage::ClearImageBuffer);
+        data.image = data.buffer->copyImage(CopyBackingStore);
+        data.imageNeedsUpdate = false;
+    }
+    ASSERT(m_svgImage->imageObserver());
+    m_svgImage->imageObserver()->animationAdvanced(m_svgImage);
+}
+
+Image* SVGImageCache::lookupOrCreateBitmapImageForRenderer(const RenderObject* renderer)
+{
+    ASSERT(renderer);
+
+    // The cache needs to know the size of the renderer before querying an image for it.
+    SizeAndZoomMap::iterator sizeIt = m_sizeAndZoomMap.find(renderer);
+    if (sizeIt == m_sizeAndZoomMap.end())
+        return Image::nullImage();
+
+    IntSize size = sizeIt->second.size;
+    float zoom = sizeIt->second.zoom;
+    ASSERT(!size.isEmpty());
+
+    // Lookup image for renderer in cache and eventually update it.
+    ImageDataMap::iterator it = m_imageDataMap.find(renderer);
+    if (it != m_imageDataMap.end()) {
+        ImageData& data = it->second;
+
+        // Common case: image size & zoom remained the same.
+        if (data.sizeAndZoom.size == size && data.sizeAndZoom.zoom == zoom)
+            return data.image.get();
+
+        // If the image size for the renderer changed, we have to delete the buffer, remove the item from the cache and recreate it.
+        delete data.buffer;
+        m_imageDataMap.remove(it);
+    }
+
+    // Create and cache new image and image buffer at requested size.
+    OwnPtr<ImageBuffer> newBuffer = ImageBuffer::create(size);
+    if (!newBuffer)
+        return Image::nullImage();
+
+    m_svgImage->drawSVGToImageBuffer(newBuffer.get(), size, zoom, SVGImage::DontClearImageBuffer);
+
+    RefPtr<Image> newImage = newBuffer->copyImage(CopyBackingStore);
+    Image* newImagePtr = newImage.get();
+    ASSERT(newImagePtr);
+
+    m_imageDataMap.add(renderer, ImageData(newBuffer.leakPtr(), newImage.release(), sizeIt->second));
+    return newImagePtr;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
diff --git a/Source/WebCore/svg/graphics/SVGImageCache.h b/Source/WebCore/svg/graphics/SVGImageCache.h
new file mode 100644 (file)
index 0000000..53d2161
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 Research In Motion Limited. 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SVGImageCache_h
+#define SVGImageCache_h
+
+#if ENABLE(SVG)
+#include "Image.h"
+#include "IntSize.h"
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class CachedImage;
+class ImageBuffer;
+class RenderObject;
+class SVGImage;
+
+class SVGImageCache {
+public:
+    ~SVGImageCache();
+
+    static PassOwnPtr<SVGImageCache> create(SVGImage* image)
+    {
+        return adoptPtr(new SVGImageCache(image));
+    }
+
+    struct SizeAndZoom {
+        SizeAndZoom()
+            : zoom(1)
+        {
+        }
+
+        SizeAndZoom(const IntSize& newSize, float newZoom)
+            : size(newSize)
+            , zoom(newZoom)
+        {
+        }
+
+        IntSize size;
+        float zoom;
+    };
+
+    void removeRendererFromCache(const RenderObject*);
+
+    void setRequestedSizeAndZoom(const RenderObject*, const SizeAndZoom&);
+    SizeAndZoom requestedSizeAndZoom(const RenderObject*) const;
+
+    Image* lookupOrCreateBitmapImageForRenderer(const RenderObject*);
+    void imageContentChanged();
+
+private:
+    SVGImageCache(SVGImage*);
+    void redrawTimerFired(Timer<SVGImageCache>*);
+
+    struct ImageData {
+        ImageData()
+            : imageNeedsUpdate(false)
+            , buffer(0)
+        {
+        }
+
+        ImageData(ImageBuffer* newBuffer, PassRefPtr<Image> newImage, const SizeAndZoom& newSizeAndZoom)
+            : imageNeedsUpdate(false)
+            , sizeAndZoom(newSizeAndZoom)
+            , buffer(newBuffer)
+            , image(newImage)
+        {
+        }
+
+        bool imageNeedsUpdate;
+        SizeAndZoom sizeAndZoom;
+
+        ImageBuffer* buffer;
+        RefPtr<Image> image;
+    };
+
+    typedef HashMap<const RenderObject*, SizeAndZoom> SizeAndZoomMap;
+    typedef HashMap<const RenderObject*, ImageData> ImageDataMap;
+
+    SVGImage* m_svgImage;
+    SizeAndZoomMap m_sizeAndZoomMap;
+    ImageDataMap m_imageDataMap;
+    Timer<SVGImageCache> m_redrawTimer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SVG)
+#endif // SVGImageCache_h
index 24566c4..dfcbed0 100644 (file)
@@ -30,6 +30,7 @@ SET(WebKit_INCLUDE_DIRECTORIES
     "${WEBCORE_DIR}/rendering/style"
     "${WEBCORE_DIR}/storage"
     "${WEBCORE_DIR}/svg"
+    "${WEBCORE_DIR}/svg/graphics"
     "${WEBCORE_DIR}/svg/properties"
     "${JAVASCRIPTCORE_DIR}"
     "${JAVASCRIPTCORE_DIR}/ForwardingHeaders"
index 7d9b205..a9e6f1d 100644 (file)
@@ -1,3 +1,12 @@
+2011-11-08  Nikolas Zimmermann  <nzimmermann@rim.com>
+
+        Switch SVGImage cache to store ImageBuffers instead of whole SVGImages, including a DOM/Render tree
+        https://bugs.webkit.org/show_bug.cgi?id=71368
+
+        Reviewed by Antti Koivisto.
+
+        * CMakeLists.txt: Add svg/graphics include, for SVGImageCache.h.
+
 2011-11-04  Tor Arne Vestbø  <tor.arne.vestbo@nokia.com>
 
         [Qt] Refactor and clean up the qmake build system