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 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: http://svn.webkit.org/repository/webkit/trunk@99539 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt
index cccc3d0..209b836 100644
--- a/Source/WebCore/CMakeLists.txt
+++ b/Source/WebCore/CMakeLists.txt
@@ -1806,6 +1806,7 @@
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
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 0266688..435c224 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -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
diff --git a/Source/WebCore/GNUmakefile.list.am b/Source/WebCore/GNUmakefile.list.am
index ca52521..bbbb85d 100644
--- a/Source/WebCore/GNUmakefile.list.am
+++ b/Source/WebCore/GNUmakefile.list.am
@@ -3536,6 +3536,8 @@
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 \
diff --git a/Source/WebCore/Target.pri b/Source/WebCore/Target.pri
index f0f11c8..898e3bc 100644
--- a/Source/WebCore/Target.pri
+++ b/Source/WebCore/Target.pri
@@ -2483,6 +2483,7 @@
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 @@
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
diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi
index a9b160c..d588cc1 100644
--- a/Source/WebCore/WebCore.gypi
+++ b/Source/WebCore/WebCore.gypi
@@ -6206,6 +6206,8 @@
'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',
diff --git a/Source/WebCore/WebCore.vcproj/WebCore.vcproj b/Source/WebCore/WebCore.vcproj/WebCore.vcproj
index 1b75e50..356b020 100755
--- a/Source/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/Source/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -67101,6 +67101,14 @@
Name="graphics"
>
<File
+ RelativePath="..\svg\graphics\SVGImageCache.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\svg\graphics\SVGImageCache.h"
+ >
+ </File>
+ <File
RelativePath="..\svg\graphics\SVGImage.cpp"
>
</File>
diff --git a/Source/WebCore/WebCore.vcproj/copyForwardingHeaders.cmd b/Source/WebCore/WebCore.vcproj/copyForwardingHeaders.cmd
index 224ce03..92a6e30 100755
--- a/Source/WebCore/WebCore.vcproj/copyForwardingHeaders.cmd
+++ b/Source/WebCore/WebCore.vcproj/copyForwardingHeaders.cmd
@@ -70,6 +70,7 @@
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"
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index a6a5b30..bb2a4c2 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -194,6 +194,8 @@
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, ); }; };
@@ -7224,6 +7226,8 @@
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>"; };
@@ -19004,6 +19008,8 @@
B255989C0D00D8B800BB825C /* filters */,
B255990B0D00D8B900BB825C /* SVGImage.cpp */,
B255990C0D00D8B900BB825C /* SVGImage.h */,
+ 08F859D21463F9CD0067D933 /* SVGImageCache.cpp */,
+ 08F859D31463F9CD0067D933 /* SVGImageCache.h */,
);
path = graphics;
sourceTree = "<group>";
@@ -24624,6 +24630,7 @@
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 */,
@@ -27480,6 +27487,7 @@
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 */,
diff --git a/Source/WebCore/css/CSSImageGeneratorValue.cpp b/Source/WebCore/css/CSSImageGeneratorValue.cpp
index 258ef0e..28486c0 100644
--- a/Source/WebCore/css/CSSImageGeneratorValue.cpp
+++ b/Source/WebCore/css/CSSImageGeneratorValue.cpp
@@ -48,7 +48,7 @@
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 @@
{
// 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)
diff --git a/Source/WebCore/loader/cache/CachedImage.cpp b/Source/WebCore/loader/cache/CachedImage.cpp
index 0cc2d8a..1c45895 100644
--- a/Source/WebCore/loader/cache/CachedImage.cpp
+++ b/Source/WebCore/loader/cache/CachedImage.cpp
@@ -90,6 +90,15 @@
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 @@
}
#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 @@
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 @@
#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::clear()
{
destroyDecodedData();
+#if ENABLE(SVG)
m_svgImageCache.clear();
+#endif
m_image = 0;
setEncodedSize(0);
}
@@ -330,7 +317,9 @@
#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 @@
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::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 @@
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 @@
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
diff --git a/Source/WebCore/loader/cache/CachedImage.h b/Source/WebCore/loader/cache/CachedImage.h
index 7cba852..bc1bfb1 100644
--- a/Source/WebCore/loader/cache/CachedImage.h
+++ b/Source/WebCore/loader/cache/CachedImage.h
@@ -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 @@
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 @@
virtual void changedInRect(const Image*, const IntRect&);
private:
- Image* lookupImageForSize(const IntSize&) const;
Image* lookupOrCreateImageForRenderer(const RenderObject*);
void createImage();
@@ -106,7 +106,9 @@
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;
};
diff --git a/Source/WebCore/page/DragController.cpp b/Source/WebCore/page/DragController.cpp
index 4d5311a..dc6c726 100644
--- a/Source/WebCore/page/DragController.cpp
+++ b/Source/WebCore/page/DragController.cpp
@@ -653,8 +653,11 @@
{
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)
diff --git a/Source/WebCore/rendering/ImageBySizeCache.cpp b/Source/WebCore/rendering/ImageBySizeCache.cpp
index d396610..615cb6d 100644
--- a/Source/WebCore/rendering/ImageBySizeCache.cpp
+++ b/Source/WebCore/rendering/ImageBySizeCache.cpp
@@ -23,7 +23,6 @@
#include "Image.h"
#include "IntSize.h"
-#include "IntSizeHash.h"
#include "RenderObject.h"
namespace WebCore {
@@ -32,7 +31,7 @@
{
}
-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 @@
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 @@
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 @@
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 @@
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
diff --git a/Source/WebCore/rendering/ImageBySizeCache.h b/Source/WebCore/rendering/ImageBySizeCache.h
index 0b19864..f5c5535 100644
--- a/Source/WebCore/rendering/ImageBySizeCache.h
+++ b/Source/WebCore/rendering/ImageBySizeCache.h
@@ -31,41 +31,29 @@
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:
diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp
index 3319787..0a70781 100644
--- a/Source/WebCore/rendering/RenderImage.cpp
+++ b/Source/WebCore/rendering/RenderImage.cpp
@@ -545,9 +545,9 @@
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;
diff --git a/Source/WebCore/rendering/RenderReplaced.cpp b/Source/WebCore/rendering/RenderReplaced.cpp
index c718c39..f2ecfba 100644
--- a/Source/WebCore/rendering/RenderReplaced.cpp
+++ b/Source/WebCore/rendering/RenderReplaced.cpp
@@ -200,10 +200,8 @@
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::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()));
diff --git a/Source/WebCore/rendering/style/StyleCachedImage.cpp b/Source/WebCore/rendering/style/StyleCachedImage.cpp
index 4078c49..1a7d9ef 100644
--- a/Source/WebCore/rendering/style/StyleCachedImage.cpp
+++ b/Source/WebCore/rendering/style/StyleCachedImage.cpp
@@ -86,7 +86,7 @@
void StyleCachedImage::removeClient(RenderObject* renderer)
{
- m_image->removeClient(renderer);
+ m_image->removeClientForRenderer(renderer);
}
PassRefPtr<Image> StyleCachedImage::image(RenderObject* renderer, const IntSize&) const
diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
index 9b6b88d..1195af4 100644
--- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp
@@ -117,7 +117,7 @@
setPreferredLogicalWidthsDirty(false);
}
-bool RenderSVGRoot::isEmbeddedThroughImageElement() const
+bool RenderSVGRoot::isEmbeddedThroughSVGImage() const
{
if (!node())
return false;
diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h
index c0335f6..2e41354 100644
--- a/Source/WebCore/rendering/svg/RenderSVGRoot.h
+++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h
@@ -39,7 +39,7 @@
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; }
diff --git a/Source/WebCore/svg/SVGSVGElement.cpp b/Source/WebCore/svg/SVGSVGElement.cpp
index efb2b2b..dfce6cd 100644
--- a/Source/WebCore/svg/SVGSVGElement.cpp
+++ b/Source/WebCore/svg/SVGSVGElement.cpp
@@ -551,23 +551,33 @@
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;
}
diff --git a/Source/WebCore/svg/SVGSVGElement.h b/Source/WebCore/svg/SVGSVGElement.h
index bc43a2d..f6170ac 100644
--- a/Source/WebCore/svg/SVGSVGElement.h
+++ b/Source/WebCore/svg/SVGSVGElement.h
@@ -72,8 +72,13 @@
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);
diff --git a/Source/WebCore/svg/graphics/SVGImage.cpp b/Source/WebCore/svg/graphics/SVGImage.cpp
index 0a333af..9466a66 100644
--- a/Source/WebCore/svg/graphics/SVGImage.cpp
+++ b/Source/WebCore/svg/graphics/SVGImage.cpp
@@ -102,43 +102,9 @@
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 @@
// 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 @@
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)
diff --git a/Source/WebCore/svg/graphics/SVGImage.h b/Source/WebCore/svg/graphics/SVGImage.h
index 638491e..1e3fe4f 100644
--- a/Source/WebCore/svg/graphics/SVGImage.h
+++ b/Source/WebCore/svg/graphics/SVGImage.h
@@ -34,6 +34,7 @@
namespace WebCore {
+class ImageBuffer;
class Page;
class RenderBox;
class SVGImageChromeClient;
@@ -45,12 +46,16 @@
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 @@
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
index 0000000..cd901f4b
--- /dev/null
+++ b/Source/WebCore/svg/graphics/SVGImageCache.cpp
@@ -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
index 0000000..53d2161
--- /dev/null
+++ b/Source/WebCore/svg/graphics/SVGImageCache.h
@@ -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