[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

zimmermann at webkit.org zimmermann at webkit.org
Wed Dec 22 11:31:46 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 032746a4b5534005a65dba80267644330524ae24
Author: zimmermann at webkit.org <zimmermann at webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Wed Jul 28 10:55:19 2010 +0000

    2010-07-28  Nikolas Zimmermann  <nzimmermann at rim.com>
    
            Reviewed by Dirk Schulze.
    
            WebKit shouldn't ignore resource cycles, but break them as Opera does
            https://bugs.webkit.org/show_bug.cgi?id=43031
    
            Don't ignore resources containing cyclic references, but break them, as discussed on SVG WG mailing lists - to be compatible with Opera which already does that.
    
            We used to lookup RenderSVGResourceContainers objects, by extracting the URI reference from the SVGRenderStyle, then utilizing getElementById() to lookup the
            node, and access its renderer. Opera ignores such references, if they point to resources that contain cyclic references. Ignoring them would mean we have
            to mutate the render style to empty the resource strings. That obviously doesn't work, as it would break expectations (getComputedStyle, etc.).
    
            Introduce a SVGResources class that stores pointers to all resources, that can be applied to a RenderObject (clipper/filter/markers/masker).
            Add a SVGResourcesCache class, which is basically a HashMap<RenderObject*, SVGResources*>. Whenever a RenderObject receives style, we extract the URI references
            from the SVGRenderStyle, look up the RenderSVGResourceContainer* objects, and store them in a SVGResources* class. Then we execute a cycle detection logic,
            which detects cyclic references and breaks them. Breaking them means just nulling the pointer to the resource in the SVGResources object. Those SVGResources
            objects are cached, and used throughout the render tree to access resources. This way it's guaranteed that all cyclic references are resolved until layout/paint
            phase begins.
    
            This is the first chunk, which just adds the new SVGResources/SVGResourcesCache/SVGResourcesCycleSolver files, and does minor cleanups.
            It's not yet glued in and doesn't affect any tests.
    
            * Android.mk: Add SVGResources.* / SVGResourcesCache.* / SVGResourcesCycleSolver.* to build.
            * CMakeLists.txt: Ditto.
            * WebCore.gypi: Ditto.
            * WebCore.pro: Ditto.
            * WebCore.vcproj/WebCore.vcproj: Ditto.
            * WebCore.xcodeproj/project.pbxproj: Ditto.
            * rendering/RenderInline.h: Make styleDidChange protected, RenderSVGInline wants to override it.
            * rendering/RenderSVGAllInOne.cpp: Add SVGResources.* / SVGResourcesCache.* / SVGResourcesCycleSolver.* to build.
            * rendering/RenderSVGHiddenContainer.h:
            (WebCore::RenderSVGHiddenContainer::isSVGHiddenContainer): Make isSVGHiddenContainer() private and renderName() public.
            * rendering/RenderSVGResourceContainer.cpp: Added. Moved most methods from the header in the implementation file.
            (WebCore::RenderSVGResourceContainer::RenderSVGResourceContainer):
            (WebCore::RenderSVGResourceContainer::~RenderSVGResourceContainer):
            (WebCore::RenderSVGResourceContainer::idChanged):
            (WebCore::RenderSVGResourceContainer::transformOnNonScalingStroke):
            (WebCore::RenderSVGResourceContainer::containsCyclicReference):
            * rendering/RenderSVGResourceContainer.h: Add stubs, that SVGResourcesCache uses - a follow-up patch will add the logic.
            (WebCore::RenderSVGResourceContainer::addClient):
            (WebCore::RenderSVGResourceContainer::removeClient):
            * rendering/SVGResources.cpp: Added. Holds a list of resources applyable to a RenderObject (fill/stroke, mask/markers/clipper/filter)
            (WebCore::paintingResourceFromSVGPaint): Helper function looking up a RenderSVGResource for a SVGPaint object.
            (WebCore::registerPendingResource): Helper function that register a RenderSVGResource as pending in the SVGDocumentExtensions.
            (WebCore::SVGResources::buildCachedResources): Build a list of resources for a RenderObject/RenderStyle pair, handles pending resources, if needed.
            (WebCore::SVGResources::invalidateClient): Helper function that calls invalidateClient() on all resources.
            (WebCore::SVGResources::resourceDestroyed): Helper function that calls invalidateClients() on a certain resource, and nulls it.
            (WebCore::SVGResources::buildSetOfResources): Helper function that stashes all resources present in the SVGResources members in a HashSet, used in SVGResourcesCycleSolver.
            (WebCore::SVGResources::resetClipper): Helper methods nulling a resource.
            (WebCore::SVGResources::resetFilter): Ditto.
            (WebCore::SVGResources::resetMarkerStart): Ditto.
            (WebCore::SVGResources::resetMarkerMid): Ditto.
            (WebCore::SVGResources::resetMarkerEnd): Ditto.
            (WebCore::SVGResources::resetMasker): Ditto.
            (WebCore::SVGResources::resetFill): Ditto.
            (WebCore::SVGResources::resetStroke): Ditto.
            (WebCore::SVGResources::dump):
            * rendering/SVGResources.h: Added.
            (WebCore::SVGResources::clipper): Accesor of the cached m_foo variable.
            (WebCore::SVGResources::filter): Ditto.
            (WebCore::SVGResources::markerStart): Ditto.
            (WebCore::SVGResources::markerMid): Ditto.
            (WebCore::SVGResources::markerEnd): Ditto.
            (WebCore::SVGResources::masker): Ditto.
            (WebCore::SVGResources::fill): Ditto.
            (WebCore::SVGResources::stroke): Ditto.
            * rendering/SVGResourcesCache.cpp: Added. Holds a HashMap<RenderObject*, SVGResources*> and utility functions that update/invalidate the cache.
            (WebCore::SVGResourcesCache::SVGResourcesCache):
            (WebCore::SVGResourcesCache::~SVGResourcesCache):
            (WebCore::SVGResourcesCache::addResourcesFromRenderObject): Build a SVGResources object for a RenderObject and adds it to the cache, then detects & breaks cycles using SVGResourcesCycleSolver.
            (WebCore::SVGResourcesCache::removeResourcesFromRenderObject): Remove a SVGResources object from the cache.
            (WebCore::resourcesCacheFromRenderObject): Helper function, retrieving a SVGResourcesCache method from a RenderObject.
            (WebCore::SVGResourcesCache::cachedResourcesForRenderObject): Returns a SVGResources object from the cache.
            (WebCore::SVGResourcesCache::clientLayoutChanged): (static) Calls invalidateClient() on all resources that are used by the passed RenderObject.
            (WebCore::SVGResourcesCache::clientStyleChanged): (static) Updates the cache (calling removeResourceFromRenderObject/addResourcesFrom...) and invalidates resources in the ancestor chain.
            (WebCore::SVGResourcesCache::clientUpdatedFromElement): (static) Does the same, without invalidating the ancestor chain.
            (WebCore::SVGResourcesCache::clientDestroyed): (static) Calls removeResourcesFromRenderObject() on the SVGResourcesCache, for the given renderer.
            (WebCore::SVGResourcesCache::resourceDestroyed): (static) Updates all SVGResources objects in the cache, that refer to the given resource.
            * rendering/SVGResourcesCache.h: Added.
            * rendering/SVGResourcesCycleSolver.cpp: Added. Detects and breaks cyclic references, just the way Opera handles it. Break cycles as they are detected.
            (WebCore::SVGResourcesCycleSolver::SVGResourcesCycleSolver):
            (WebCore::SVGResourcesCycleSolver::~SVGResourcesCycleSolver):
            (WebCore::SVGResourcesCycleSolver::resourceContainsCycles): Operates only on the render tree
            (WebCore::targetReferenceFromResource): Helper method for chainableResourceContainsCycles().
            (WebCore::setFollowLinkForChainableResource): Ditto.
            (WebCore::SVGResourcesCycleSolver::chainableResourceContainsCycles): Handles cycles for resources that are chainable through xlink:href (filter/gradient/pattern).
            (WebCore::SVGResourcesCycleSolver::resolveCycles): Main method executing the cycle breaking logic, utilizing (chainableResource)resourceContainsCycles.
            (WebCore::SVGResourcesCycleSolver::breakCycle): Nulls a resource in the given SVGResources* object, to avoid using an invalid resource while rendering/layouting.
            * rendering/SVGResourcesCycleSolver.h: Added.
            * svg/SVGDocumentExtensions.cpp:
            (WebCore::SVGDocumentExtensions::SVGDocumentExtensions): Create SVGResourcesCache object once per SVGDocumentExtensions.
            * svg/SVGDocumentExtensions.h:
            (WebCore::SVGDocumentExtensions::resourcesCache): Expose accesor method for the SVGResourcesCache.
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@64196 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/Android.mk b/WebCore/Android.mk
index da7362c..ce10769 100644
--- a/WebCore/Android.mk
+++ b/WebCore/Android.mk
@@ -638,6 +638,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
 	rendering/RenderSVGModelObject.cpp \
 	rendering/RenderSVGResource.cpp \
 	rendering/RenderSVGResourceClipper.cpp \
+	rendering/RenderSVGResourceContainer.cpp \
 	rendering/RenderSVGResourceFilter.cpp \
 	rendering/RenderSVGResourceGradient.cpp \
 	rendering/RenderSVGResourceLinearGradient.cpp \
@@ -687,6 +688,9 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
 	rendering/SVGMarkerLayoutInfo.cpp \
 	rendering/SVGRenderSupport.cpp \
 	rendering/SVGRenderTreeAsText.cpp \
+	rendering/SVGResources.cpp \
+	rendering/SVGResourcesCache.cpp \
+	rendering/SVGResourcesCycleSolver.cpp \
 	rendering/SVGRootInlineBox.cpp \
 	rendering/SVGShadowTreeElements.cpp \
 	rendering/SVGTextChunkLayoutInfo.cpp \
diff --git a/WebCore/CMakeLists.txt b/WebCore/CMakeLists.txt
index 3bfa0a9..755a291 100644
--- a/WebCore/CMakeLists.txt
+++ b/WebCore/CMakeLists.txt
@@ -1544,6 +1544,7 @@ IF (ENABLE_SVG)
         rendering/RenderSVGModelObject.cpp
         rendering/RenderSVGResource.cpp
         rendering/RenderSVGResourceClipper.cpp
+        rendering/RenderSVGResourceContainer.cpp
         rendering/RenderSVGResourceFilter.cpp
         rendering/RenderSVGResourceGradient.cpp
         rendering/RenderSVGResourceLinearGradient.cpp
@@ -1566,6 +1567,9 @@ IF (ENABLE_SVG)
         rendering/SVGMarkerLayoutInfo.cpp
         rendering/SVGRenderSupport.cpp
         rendering/SVGRenderTreeAsText.cpp
+        rendering/SVGResources.cpp
+        rendering/SVGResourcesCache.cpp
+        rendering/SVGResourcesCycleSolver.cpp
         rendering/SVGRootInlineBox.cpp
         rendering/SVGShadowTreeElements.cpp
         rendering/SVGTextChunkLayoutInfo.cpp
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index aab59ba..282b713 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,98 @@
+2010-07-28  Nikolas Zimmermann  <nzimmermann at rim.com>
+
+        Reviewed by Dirk Schulze.
+
+        WebKit shouldn't ignore resource cycles, but break them as Opera does
+        https://bugs.webkit.org/show_bug.cgi?id=43031
+
+        Don't ignore resources containing cyclic references, but break them, as discussed on SVG WG mailing lists - to be compatible with Opera which already does that.
+
+        We used to lookup RenderSVGResourceContainers objects, by extracting the URI reference from the SVGRenderStyle, then utilizing getElementById() to lookup the
+        node, and access its renderer. Opera ignores such references, if they point to resources that contain cyclic references. Ignoring them would mean we have
+        to mutate the render style to empty the resource strings. That obviously doesn't work, as it would break expectations (getComputedStyle, etc.).
+
+        Introduce a SVGResources class that stores pointers to all resources, that can be applied to a RenderObject (clipper/filter/markers/masker).
+        Add a SVGResourcesCache class, which is basically a HashMap<RenderObject*, SVGResources*>. Whenever a RenderObject receives style, we extract the URI references
+        from the SVGRenderStyle, look up the RenderSVGResourceContainer* objects, and store them in a SVGResources* class. Then we execute a cycle detection logic,
+        which detects cyclic references and breaks them. Breaking them means just nulling the pointer to the resource in the SVGResources object. Those SVGResources
+        objects are cached, and used throughout the render tree to access resources. This way it's guaranteed that all cyclic references are resolved until layout/paint
+        phase begins.
+
+        This is the first chunk, which just adds the new SVGResources/SVGResourcesCache/SVGResourcesCycleSolver files, and does minor cleanups.
+        It's not yet glued in and doesn't affect any tests.
+
+        * Android.mk: Add SVGResources.* / SVGResourcesCache.* / SVGResourcesCycleSolver.* to build.
+        * CMakeLists.txt: Ditto.
+        * WebCore.gypi: Ditto.
+        * WebCore.pro: Ditto.
+        * WebCore.vcproj/WebCore.vcproj: Ditto. 
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+        * rendering/RenderInline.h: Make styleDidChange protected, RenderSVGInline wants to override it.
+        * rendering/RenderSVGAllInOne.cpp: Add SVGResources.* / SVGResourcesCache.* / SVGResourcesCycleSolver.* to build.
+        * rendering/RenderSVGHiddenContainer.h:
+        (WebCore::RenderSVGHiddenContainer::isSVGHiddenContainer): Make isSVGHiddenContainer() private and renderName() public.
+        * rendering/RenderSVGResourceContainer.cpp: Added. Moved most methods from the header in the implementation file.
+        (WebCore::RenderSVGResourceContainer::RenderSVGResourceContainer):
+        (WebCore::RenderSVGResourceContainer::~RenderSVGResourceContainer):
+        (WebCore::RenderSVGResourceContainer::idChanged):
+        (WebCore::RenderSVGResourceContainer::transformOnNonScalingStroke):
+        (WebCore::RenderSVGResourceContainer::containsCyclicReference):
+        * rendering/RenderSVGResourceContainer.h: Add stubs, that SVGResourcesCache uses - a follow-up patch will add the logic.
+        (WebCore::RenderSVGResourceContainer::addClient):
+        (WebCore::RenderSVGResourceContainer::removeClient):
+        * rendering/SVGResources.cpp: Added. Holds a list of resources applyable to a RenderObject (fill/stroke, mask/markers/clipper/filter)
+        (WebCore::paintingResourceFromSVGPaint): Helper function looking up a RenderSVGResource for a SVGPaint object.
+        (WebCore::registerPendingResource): Helper function that register a RenderSVGResource as pending in the SVGDocumentExtensions. 
+        (WebCore::SVGResources::buildCachedResources): Build a list of resources for a RenderObject/RenderStyle pair, handles pending resources, if needed.
+        (WebCore::SVGResources::invalidateClient): Helper function that calls invalidateClient() on all resources.
+        (WebCore::SVGResources::resourceDestroyed): Helper function that calls invalidateClients() on a certain resource, and nulls it.
+        (WebCore::SVGResources::buildSetOfResources): Helper function that stashes all resources present in the SVGResources members in a HashSet, used in SVGResourcesCycleSolver.
+        (WebCore::SVGResources::resetClipper): Helper methods nulling a resource.
+        (WebCore::SVGResources::resetFilter): Ditto.
+        (WebCore::SVGResources::resetMarkerStart): Ditto.
+        (WebCore::SVGResources::resetMarkerMid): Ditto.
+        (WebCore::SVGResources::resetMarkerEnd): Ditto.
+        (WebCore::SVGResources::resetMasker): Ditto.
+        (WebCore::SVGResources::resetFill): Ditto.
+        (WebCore::SVGResources::resetStroke): Ditto.
+        (WebCore::SVGResources::dump):
+        * rendering/SVGResources.h: Added.
+        (WebCore::SVGResources::clipper): Accesor of the cached m_foo variable.
+        (WebCore::SVGResources::filter): Ditto.
+        (WebCore::SVGResources::markerStart): Ditto.
+        (WebCore::SVGResources::markerMid): Ditto.
+        (WebCore::SVGResources::markerEnd): Ditto.
+        (WebCore::SVGResources::masker): Ditto.
+        (WebCore::SVGResources::fill): Ditto.
+        (WebCore::SVGResources::stroke): Ditto.
+        * rendering/SVGResourcesCache.cpp: Added. Holds a HashMap<RenderObject*, SVGResources*> and utility functions that update/invalidate the cache.
+        (WebCore::SVGResourcesCache::SVGResourcesCache):
+        (WebCore::SVGResourcesCache::~SVGResourcesCache):
+        (WebCore::SVGResourcesCache::addResourcesFromRenderObject): Build a SVGResources object for a RenderObject and adds it to the cache, then detects & breaks cycles using SVGResourcesCycleSolver.
+        (WebCore::SVGResourcesCache::removeResourcesFromRenderObject): Remove a SVGResources object from the cache.
+        (WebCore::resourcesCacheFromRenderObject): Helper function, retrieving a SVGResourcesCache method from a RenderObject.
+        (WebCore::SVGResourcesCache::cachedResourcesForRenderObject): Returns a SVGResources object from the cache.
+        (WebCore::SVGResourcesCache::clientLayoutChanged): (static) Calls invalidateClient() on all resources that are used by the passed RenderObject.
+        (WebCore::SVGResourcesCache::clientStyleChanged): (static) Updates the cache (calling removeResourceFromRenderObject/addResourcesFrom...) and invalidates resources in the ancestor chain.
+        (WebCore::SVGResourcesCache::clientUpdatedFromElement): (static) Does the same, without invalidating the ancestor chain.
+        (WebCore::SVGResourcesCache::clientDestroyed): (static) Calls removeResourcesFromRenderObject() on the SVGResourcesCache, for the given renderer.
+        (WebCore::SVGResourcesCache::resourceDestroyed): (static) Updates all SVGResources objects in the cache, that refer to the given resource.
+        * rendering/SVGResourcesCache.h: Added.
+        * rendering/SVGResourcesCycleSolver.cpp: Added. Detects and breaks cyclic references, just the way Opera handles it. Break cycles as they are detected.
+        (WebCore::SVGResourcesCycleSolver::SVGResourcesCycleSolver):
+        (WebCore::SVGResourcesCycleSolver::~SVGResourcesCycleSolver):
+        (WebCore::SVGResourcesCycleSolver::resourceContainsCycles): Operates only on the render tree
+        (WebCore::targetReferenceFromResource): Helper method for chainableResourceContainsCycles().
+        (WebCore::setFollowLinkForChainableResource): Ditto.
+        (WebCore::SVGResourcesCycleSolver::chainableResourceContainsCycles): Handles cycles for resources that are chainable through xlink:href (filter/gradient/pattern).
+        (WebCore::SVGResourcesCycleSolver::resolveCycles): Main method executing the cycle breaking logic, utilizing (chainableResource)resourceContainsCycles.
+        (WebCore::SVGResourcesCycleSolver::breakCycle): Nulls a resource in the given SVGResources* object, to avoid using an invalid resource while rendering/layouting.
+        * rendering/SVGResourcesCycleSolver.h: Added.
+        * svg/SVGDocumentExtensions.cpp:
+        (WebCore::SVGDocumentExtensions::SVGDocumentExtensions): Create SVGResourcesCache object once per SVGDocumentExtensions.
+        * svg/SVGDocumentExtensions.h:
+        (WebCore::SVGDocumentExtensions::resourcesCache): Expose accesor method for the SVGResourcesCache.
+
 2010-07-28  Zoltan Herczeg  <zherczeg at webkit.org>
 
         Reviewed by Nikolas Zimmermann.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index aafb222..698e302 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -3312,6 +3312,8 @@
             'rendering/RenderSVGResource.h',
             'rendering/RenderSVGResourceClipper.cpp',
             'rendering/RenderSVGResourceClipper.h',
+            'rendering/RenderSVGResourceContainer.cpp',
+            'rendering/RenderSVGResourceContainer.h',
             'rendering/RenderSVGResourceFilter.cpp',
             'rendering/RenderSVGResourceFilter.h',
             'rendering/RenderSVGResourceGradient.cpp',
@@ -3418,6 +3420,12 @@
             'rendering/SVGRenderSupport.h',
             'rendering/SVGRenderTreeAsText.cpp',
             'rendering/SVGRenderTreeAsText.h',
+            'rendering/SVGResources.cpp',
+            'rendering/SVGResources.h',
+            'rendering/SVGResourcesCache.cpp',
+            'rendering/SVGResourcesCache.h',
+            'rendering/SVGResourcesCycleSolver.cpp',
+            'rendering/SVGResourcesCycleSolver.h',
             'rendering/SVGRootInlineBox.cpp',
             'rendering/SVGRootInlineBox.h',
             'rendering/SVGShadowTreeElements.cpp',
diff --git a/WebCore/WebCore.pro b/WebCore/WebCore.pro
index 0751809..b7f152e 100644
--- a/WebCore/WebCore.pro
+++ b/WebCore/WebCore.pro
@@ -1826,6 +1826,7 @@ HEADERS += \
     rendering/RenderSVGModelObject.h \
     rendering/RenderSVGResource.h \
     rendering/RenderSVGResourceClipper.h \
+    rendering/RenderSVGResourceContainer.h \
     rendering/RenderSVGResourceFilter.h \ 
     rendering/RenderSVGResourceGradient.h \
     rendering/RenderSVGResourceLinearGradient.h \
@@ -1894,6 +1895,9 @@ HEADERS += \
     rendering/SVGMarkerLayoutInfo.h \
     rendering/SVGRenderSupport.h \
     rendering/SVGRenderTreeAsText.h \
+    rendering/SVGResources.h \
+    rendering/SVGResourcesCache.h \
+    rendering/SVGResourcesCycleSolver.h \
     rendering/SVGRootInlineBox.h \
     rendering/SVGShadowTreeElements.h \
     rendering/SVGTextChunkLayoutInfo.h \
@@ -2906,6 +2910,7 @@ contains(DEFINES, ENABLE_SVG=1) {
         rendering/RenderSVGModelObject.cpp \
         rendering/RenderSVGResource.cpp \
         rendering/RenderSVGResourceClipper.cpp \
+        rendering/RenderSVGResourceContainer.cpp \
         rendering/RenderSVGResourceFilter.cpp \
         rendering/RenderSVGResourceGradient.cpp \
         rendering/RenderSVGResourceLinearGradient.cpp \
@@ -2927,6 +2932,9 @@ contains(DEFINES, ENABLE_SVG=1) {
         rendering/SVGInlineTextBox.cpp \
         rendering/SVGMarkerLayoutInfo.cpp \
         rendering/SVGRenderSupport.cpp \
+        rendering/SVGResources.cpp \
+        rendering/SVGResourcesCache.cpp \
+        rendering/SVGResourcesCycleSolver.cpp \
         rendering/SVGRootInlineBox.cpp \
         rendering/SVGShadowTreeElements.cpp \
         rendering/SVGTextChunkLayoutInfo.cpp \
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 89c07d5..167ba8c 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -29885,6 +29885,62 @@
 				>
 			</File>
 			<File
+				RelativePath="..\rendering\RenderSVGResourceContainer.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Internal|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_All|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\rendering\RenderSVGResourceContainer.h"
+				>
+			</File>
+			<File
 				RelativePath="..\rendering\RenderSVGResourceFilter.cpp"
 				>
 				<FileConfiguration
@@ -31359,6 +31415,174 @@
 				>
 			</File>
 			<File
+				RelativePath="..\rendering\SVGResources.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Internal|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_All|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\rendering\SVGResources.h"
+				>
+			</File>
+			<File
+				RelativePath="..\rendering\SVGResourcesCache.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Internal|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_All|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\rendering\SVGResourcesCache.h"
+				>
+			</File>
+			<File
+				RelativePath="..\rendering\SVGResourcesCycleSolver.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Internal|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release_Cairo|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug_All|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
+				RelativePath="..\rendering\SVGResourcesCycleSolver.h"
+				>
+			</File>
+			<File
 				RelativePath="..\rendering\SVGRootInlineBox.cpp"
 				>
 				<FileConfiguration
diff --git a/WebCore/WebCore.xcodeproj/project.pbxproj b/WebCore/WebCore.xcodeproj/project.pbxproj
index 945aa5d..30c8196 100644
--- a/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -99,6 +99,10 @@
 		084CE5CC0F27DADC00E6240E /* WMLOptGroupElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 084CE5C80F27DADC00E6240E /* WMLOptGroupElement.h */; };
 		084CE5CD0F27DADC00E6240E /* WMLOptionElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 084CE5C90F27DADC00E6240E /* WMLOptionElement.cpp */; };
 		084CE5CE0F27DADC00E6240E /* WMLOptionElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 084CE5CA0F27DADC00E6240E /* WMLOptionElement.h */; };
+		084D0E3C11F5816100081E1A /* SVGResources.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 084D0E3811F5816100081E1A /* SVGResources.cpp */; };
+		084D0E3D11F5816100081E1A /* SVGResources.h in Headers */ = {isa = PBXBuildFile; fileRef = 084D0E3911F5816100081E1A /* SVGResources.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		084D0E3E11F5816100081E1A /* SVGResourcesCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 084D0E3A11F5816100081E1A /* SVGResourcesCache.cpp */; };
+		084D0E3F11F5816100081E1A /* SVGResourcesCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 084D0E3B11F5816100081E1A /* SVGResourcesCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		084D2833110A7FCB0038239A /* SVGAnimatedPropertySynchronizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 084D2831110A7FCB0038239A /* SVGAnimatedPropertySynchronizer.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		084D2834110A7FCB0038239A /* SVGAnimatedPropertyTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 084D2832110A7FCB0038239A /* SVGAnimatedPropertyTraits.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		084DBAA10ED39D360038C226 /* WMLVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 084DBA9D0ED39D350038C226 /* WMLVariables.cpp */; };
@@ -112,10 +116,13 @@
 		08591AA50F085C4E009BACB1 /* InputElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 08591AA40F085C4E009BACB1 /* InputElement.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		085AFDC80F2977350061F2B3 /* WMLFormControlElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 085AFDC60F2977350061F2B3 /* WMLFormControlElement.cpp */; };
 		085AFDC90F2977350061F2B3 /* WMLFormControlElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 085AFDC70F2977350061F2B3 /* WMLFormControlElement.h */; settings = {ATTRIBUTES = (); }; };
+		085B05C211FAE16C004D65F6 /* SVGResourcesCycleSolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 085B05C011FAE16C004D65F6 /* SVGResourcesCycleSolver.cpp */; };
+		085B05C311FAE16C004D65F6 /* SVGResourcesCycleSolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 085B05C111FAE16C004D65F6 /* SVGResourcesCycleSolver.h */; };
 		085B92BA0EFDE73D00E6123C /* FormDataBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 085B92B80EFDE73D00E6123C /* FormDataBuilder.cpp */; };
 		085B92BB0EFDE73D00E6123C /* FormDataBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 085B92B90EFDE73D00E6123C /* FormDataBuilder.h */; settings = {ATTRIBUTES = (); }; };
 		0865CCE60EDDF51B00DF9EC3 /* WMLNoopElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0865CCE40EDDF51B00DF9EC3 /* WMLNoopElement.cpp */; };
 		0865CCE70EDDF51B00DF9EC3 /* WMLNoopElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 0865CCE50EDDF51B00DF9EC3 /* WMLNoopElement.h */; };
+		086A400611F6D6B7002CEC53 /* RenderSVGResourceContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 086A400511F6D6B7002CEC53 /* RenderSVGResourceContainer.cpp */; };
 		08700BE70F086C5300919419 /* InputElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08700BE60F086C5300919419 /* InputElement.cpp */; };
 		087281550F26B9B600AFC596 /* OptionElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 087281510F26B9B600AFC596 /* OptionElement.cpp */; };
 		087281560F26B9B600AFC596 /* OptionElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 087281520F26B9B600AFC596 /* OptionElement.h */; };
@@ -5754,6 +5761,10 @@
 		084CE5C80F27DADC00E6240E /* WMLOptGroupElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLOptGroupElement.h; sourceTree = "<group>"; };
 		084CE5C90F27DADC00E6240E /* WMLOptionElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLOptionElement.cpp; sourceTree = "<group>"; };
 		084CE5CA0F27DADC00E6240E /* WMLOptionElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLOptionElement.h; sourceTree = "<group>"; };
+		084D0E3811F5816100081E1A /* SVGResources.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGResources.cpp; sourceTree = "<group>"; };
+		084D0E3911F5816100081E1A /* SVGResources.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGResources.h; sourceTree = "<group>"; };
+		084D0E3A11F5816100081E1A /* SVGResourcesCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGResourcesCache.cpp; sourceTree = "<group>"; };
+		084D0E3B11F5816100081E1A /* SVGResourcesCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGResourcesCache.h; sourceTree = "<group>"; };
 		084D2831110A7FCB0038239A /* SVGAnimatedPropertySynchronizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimatedPropertySynchronizer.h; sourceTree = "<group>"; };
 		084D2832110A7FCB0038239A /* SVGAnimatedPropertyTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimatedPropertyTraits.h; sourceTree = "<group>"; };
 		084DBA9D0ED39D350038C226 /* WMLVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLVariables.cpp; sourceTree = "<group>"; };
@@ -5767,10 +5778,13 @@
 		08591AA40F085C4E009BACB1 /* InputElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InputElement.h; sourceTree = "<group>"; };
 		085AFDC60F2977350061F2B3 /* WMLFormControlElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLFormControlElement.cpp; sourceTree = "<group>"; };
 		085AFDC70F2977350061F2B3 /* WMLFormControlElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLFormControlElement.h; sourceTree = "<group>"; };
+		085B05C011FAE16C004D65F6 /* SVGResourcesCycleSolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGResourcesCycleSolver.cpp; sourceTree = "<group>"; };
+		085B05C111FAE16C004D65F6 /* SVGResourcesCycleSolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGResourcesCycleSolver.h; sourceTree = "<group>"; };
 		085B92B80EFDE73D00E6123C /* FormDataBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormDataBuilder.cpp; sourceTree = "<group>"; };
 		085B92B90EFDE73D00E6123C /* FormDataBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormDataBuilder.h; sourceTree = "<group>"; };
 		0865CCE40EDDF51B00DF9EC3 /* WMLNoopElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLNoopElement.cpp; sourceTree = "<group>"; };
 		0865CCE50EDDF51B00DF9EC3 /* WMLNoopElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLNoopElement.h; sourceTree = "<group>"; };
+		086A400511F6D6B7002CEC53 /* RenderSVGResourceContainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGResourceContainer.cpp; sourceTree = "<group>"; };
 		08700BE60F086C5300919419 /* InputElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InputElement.cpp; sourceTree = "<group>"; };
 		087281510F26B9B600AFC596 /* OptionElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OptionElement.cpp; sourceTree = "<group>"; };
 		087281520F26B9B600AFC596 /* OptionElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionElement.h; sourceTree = "<group>"; };
@@ -16766,6 +16780,7 @@
 				083192A7112B43050083C3B9 /* RenderSVGResource.h */,
 				84BDA16911358D2A00DBF64C /* RenderSVGResourceClipper.cpp */,
 				84BDA16A11358D2A00DBF64C /* RenderSVGResourceClipper.h */,
+				086A400511F6D6B7002CEC53 /* RenderSVGResourceContainer.cpp */,
 				08082372117987C100241DE8 /* RenderSVGResourceContainer.h */,
 				841FDC241178C9BE00F8AC9B /* RenderSVGResourceFilter.cpp */,
 				841FDC251178C9BE00F8AC9B /* RenderSVGResourceFilter.h */,
@@ -16852,6 +16867,12 @@
 				A8F4FB930C169E7B002AFED5 /* SVGRenderSupport.h */,
 				B2EBDC9A0AF77E3400AE4A68 /* SVGRenderTreeAsText.cpp */,
 				B2EBDC9B0AF77E3400AE4A68 /* SVGRenderTreeAsText.h */,
+				084D0E3811F5816100081E1A /* SVGResources.cpp */,
+				084D0E3911F5816100081E1A /* SVGResources.h */,
+				084D0E3A11F5816100081E1A /* SVGResourcesCache.cpp */,
+				084D0E3B11F5816100081E1A /* SVGResourcesCache.h */,
+				085B05C011FAE16C004D65F6 /* SVGResourcesCycleSolver.cpp */,
+				085B05C111FAE16C004D65F6 /* SVGResourcesCycleSolver.h */,
 				853CA9E40AEEC608002372DC /* SVGRootInlineBox.cpp */,
 				853CA9E50AEEC608002372DC /* SVGRootInlineBox.h */,
 				08DAB9C01103D9C1003E7ABA /* SVGShadowTreeElements.cpp */,
@@ -19847,6 +19868,9 @@
 				E1BE512E0CF6C512002EA959 /* XSLTUnicodeSort.h in Headers */,
 				97DD4D870FDF4D6E00ECF9A4 /* XSSAuditor.h in Headers */,
 				CE172E011136E8CE0062A533 /* ZoomMode.h in Headers */,
+				084D0E3D11F5816100081E1A /* SVGResources.h in Headers */,
+				084D0E3F11F5816100081E1A /* SVGResourcesCache.h in Headers */,
+				085B05C311FAE16C004D65F6 /* SVGResourcesCycleSolver.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -22242,6 +22266,10 @@
 				93F19B0508245E59001E9ABC /* XSLTProcessorLibxslt.cpp in Sources */,
 				E1BE512D0CF6C512002EA959 /* XSLTUnicodeSort.cpp in Sources */,
 				97DD4D860FDF4D6E00ECF9A4 /* XSSAuditor.cpp in Sources */,
+				084D0E3C11F5816100081E1A /* SVGResources.cpp in Sources */,
+				084D0E3E11F5816100081E1A /* SVGResourcesCache.cpp in Sources */,
+				086A400611F6D6B7002CEC53 /* RenderSVGResourceContainer.cpp in Sources */,
+				085B05C211FAE16C004D65F6 /* SVGResourcesCycleSolver.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/WebCore/rendering/RenderInline.h b/WebCore/rendering/RenderInline.h
index a719a50..71a8a89 100644
--- a/WebCore/rendering/RenderInline.h
+++ b/WebCore/rendering/RenderInline.h
@@ -74,6 +74,9 @@ public:
     int verticalPositionFromCache(bool firstLine) const;
     void invalidateVerticalPosition() { m_verticalPosition = PositionUndefined; }
 
+protected:
+    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+
 private:
     virtual RenderObjectChildList* virtualChildren() { return children(); }
     virtual const RenderObjectChildList* virtualChildren() const { return children(); }
@@ -139,7 +142,6 @@ private:
     virtual void addDashboardRegions(Vector<DashboardRegionValue>&);
 #endif
     
-    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
     virtual void updateBoxModelInfoFromStyle();
     
     static RenderInline* cloneInline(RenderInline* src);
diff --git a/WebCore/rendering/RenderSVGAllInOne.cpp b/WebCore/rendering/RenderSVGAllInOne.cpp
index da86f84..fa5709e 100644
--- a/WebCore/rendering/RenderSVGAllInOne.cpp
+++ b/WebCore/rendering/RenderSVGAllInOne.cpp
@@ -35,6 +35,7 @@
 #include "RenderSVGModelObject.cpp"
 #include "RenderSVGResource.cpp"
 #include "RenderSVGResourceClipper.cpp"
+#include "RenderSVGResourceContainer.cpp"
 #include "RenderSVGResourceFilter.cpp"
 #include "RenderSVGResourceGradient.cpp"
 #include "RenderSVGResourceLinearGradient.cpp"
@@ -57,6 +58,9 @@
 #include "SVGMarkerLayoutInfo.cpp"
 #include "SVGRenderSupport.cpp"
 #include "SVGRenderTreeAsText.cpp"
+#include "SVGResources.cpp"
+#include "SVGResourcesCache.cpp"
+#include "SVGResourcesCycleSolver.cpp"
 #include "SVGRootInlineBox.cpp"
 #include "SVGShadowTreeElements.cpp"
 #include "SVGTextChunkLayoutInfo.cpp"
diff --git a/WebCore/rendering/RenderSVGHiddenContainer.h b/WebCore/rendering/RenderSVGHiddenContainer.h
index c446f11..297a738 100644
--- a/WebCore/rendering/RenderSVGHiddenContainer.h
+++ b/WebCore/rendering/RenderSVGHiddenContainer.h
@@ -37,11 +37,10 @@ namespace WebCore {
     public:
         RenderSVGHiddenContainer(SVGStyledElement*);
 
-    private:
-        virtual bool isSVGHiddenContainer() const { return true; }
-
         virtual const char* renderName() const { return "RenderSVGHiddenContainer"; }
 
+    private:
+        virtual bool isSVGHiddenContainer() const { return true; }
         virtual bool requiresLayer() const { return false; }
 
         virtual void layout();
diff --git a/WebCore/rendering/RenderSVGResourceContainer.cpp b/WebCore/rendering/RenderSVGResourceContainer.cpp
new file mode 100644
index 0000000..3707797
--- /dev/null
+++ b/WebCore/rendering/RenderSVGResourceContainer.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. 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"
+
+#if ENABLE(SVG)
+#include "RenderSVGResourceContainer.h"
+
+#include "RenderSVGShadowTreeRootContainer.h"
+#include "SVGStyledTransformableElement.h"
+
+namespace WebCore {
+
+RenderSVGResourceContainer::RenderSVGResourceContainer(SVGStyledElement* node)
+    : RenderSVGHiddenContainer(node)
+    , RenderSVGResource()
+    , m_id(node->hasID() ? node->getIdAttribute() : nullAtom)
+{
+    ASSERT(node->document());
+    node->document()->accessSVGExtensions()->addResource(m_id, this);
+}
+
+RenderSVGResourceContainer::~RenderSVGResourceContainer()
+{
+    ASSERT(node());
+    ASSERT(node()->document());
+    node()->document()->accessSVGExtensions()->removeResource(m_id);
+}
+
+void RenderSVGResourceContainer::idChanged()
+{
+    ASSERT(node());
+    ASSERT(node()->document());
+    SVGDocumentExtensions* extensions = node()->document()->accessSVGExtensions();
+
+    // Remove old id, that is guaranteed to be present in cache
+    extensions->removeResource(m_id);
+    m_id = static_cast<Element*>(node())->getIdAttribute();
+
+    // It's possible that an element is referencing us with the new id, and has to be notified that we're existing now
+    if (extensions->isPendingResource(m_id)) {
+        OwnPtr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(m_id));
+        if (clients->isEmpty())
+            return;
+
+        HashSet<SVGStyledElement*>::const_iterator it = clients->begin();
+        const HashSet<SVGStyledElement*>::const_iterator end = clients->end();
+
+        for (; it != end; ++it) {
+            if (RenderObject* renderer = (*it)->renderer())
+                renderer->setNeedsLayout(true);
+        }
+    }
+
+    // Recache us with the new id
+    extensions->addResource(m_id, this);
+}
+
+AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderObject* object, const AffineTransform& resourceTransform)
+{
+    if (!object->isRenderPath())
+        return resourceTransform;
+
+    SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node());
+    AffineTransform transform = resourceTransform;
+    transform.multiply(element->getScreenCTM());
+    return transform;
+}
+
+bool RenderSVGResourceContainer::containsCyclicReference(const Node* startNode) const
+{
+    ASSERT(startNode->document());
+
+    for (Node* node = startNode->firstChild(); node; node = node->nextSibling()) {
+        if (!node->isSVGElement())
+            continue;
+
+        RenderObject* renderer = node->renderer();
+        if (!renderer)
+            continue;
+
+        RenderStyle* style = renderer->style();
+        if (!style)
+            continue;
+
+        const SVGRenderStyle* svgStyle = style->svgStyle();
+        ASSERT(svgStyle);
+
+        // Let the class inheriting from us decide whether the child element references ourselves.
+        if (childElementReferencesResource(svgStyle, m_id))
+            return true;
+
+        // Dive into shadow tree to check for cycles there.
+        if (node->hasTagName(SVGNames::useTag)) {
+            ASSERT(renderer->isSVGShadowTreeRootContainer());
+            if (Node* shadowRoot = static_cast<RenderSVGShadowTreeRootContainer*>(renderer)->rootElement()) {
+                if (containsCyclicReference(shadowRoot))
+                    return true;
+            }
+
+        }
+
+        if (node->hasChildNodes()) {
+            if (containsCyclicReference(node))
+                return true;
+        }
+    }
+
+    return false;
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/RenderSVGResourceContainer.h b/WebCore/rendering/RenderSVGResourceContainer.h
index 5f1c828..d57b1db 100644
--- a/WebCore/rendering/RenderSVGResourceContainer.h
+++ b/WebCore/rendering/RenderSVGResourceContainer.h
@@ -33,50 +33,10 @@ namespace WebCore {
 class RenderSVGResourceContainer : public RenderSVGHiddenContainer,
                                    public RenderSVGResource {
 public:
-    RenderSVGResourceContainer(SVGStyledElement* node)
-        : RenderSVGHiddenContainer(node)
-        , RenderSVGResource()
-        , m_id(node->hasID() ? node->getIdAttribute() : nullAtom)
-    {
-        ASSERT(node->document());
-        node->document()->accessSVGExtensions()->addResource(m_id, this);
-    }
-
-    virtual ~RenderSVGResourceContainer()
-    {
-        ASSERT(node());
-        ASSERT(node()->document());
-        node()->document()->accessSVGExtensions()->removeResource(m_id);
-    }
-
-    void idChanged()
-    {
-        ASSERT(node());
-        ASSERT(node()->document());
-        SVGDocumentExtensions* extensions = node()->document()->accessSVGExtensions();
-
-        // Remove old id, that is guaranteed to be present in cache
-        extensions->removeResource(m_id);
-        m_id = static_cast<Element*>(node())->getIdAttribute();
-
-        // It's possible that an element is referencing us with the new id, and has to be notified that we're existing now
-        if (extensions->isPendingResource(m_id)) {
-            OwnPtr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(m_id));
-            if (clients->isEmpty())
-                return;
-
-            HashSet<SVGStyledElement*>::const_iterator it = clients->begin();
-            const HashSet<SVGStyledElement*>::const_iterator end = clients->end();
-
-            for (; it != end; ++it) {
-                if (RenderObject* renderer = (*it)->renderer())
-                    renderer->setNeedsLayout(true);
-            }
-        }
-
-        // Recache us with the new id
-        extensions->addResource(m_id, this);
-    }
+    RenderSVGResourceContainer(SVGStyledElement*);
+    virtual ~RenderSVGResourceContainer();
+
+    void idChanged();
 
     virtual bool isSVGResourceContainer() const { return true; }
     virtual bool drawsContents() { return false; }
@@ -84,58 +44,16 @@ public:
     virtual RenderSVGResourceContainer* toRenderSVGResourceContainer() { return this; }
     virtual bool childElementReferencesResource(const SVGRenderStyle*, const String&) const { return false; }
 
-    static AffineTransform transformOnNonScalingStroke(RenderObject* object, const AffineTransform resourceTransform)
-    {
-        if (!object->isRenderPath())
-            return resourceTransform;
-
-        SVGStyledTransformableElement* element = static_cast<SVGStyledTransformableElement*>(object->node());
-        AffineTransform transform = resourceTransform;
-        transform.multiply(element->getScreenCTM());
-        return transform;
-    }
-
-    bool containsCyclicReference(const Node* startNode) const
-    {
-        ASSERT(startNode->document());
-    
-        for (Node* node = startNode->firstChild(); node; node = node->nextSibling()) {
-            if (!node->isSVGElement())
-                continue;
-    
-            RenderObject* renderer = node->renderer();
-            if (!renderer)
-                continue;
-    
-            RenderStyle* style = renderer->style();
-            if (!style)
-                continue;
-    
-            const SVGRenderStyle* svgStyle = style->svgStyle();
-            ASSERT(svgStyle);
-    
-            // Let the class inheriting from us decide whether the child element references ourselves.
-            if (childElementReferencesResource(svgStyle, m_id))
-                return true;
-
-            // Dive into shadow tree to check for cycles there.
-            if (node->hasTagName(SVGNames::useTag)) {
-                ASSERT(renderer->isSVGShadowTreeRootContainer());
-                if (Node* shadowRoot = static_cast<RenderSVGShadowTreeRootContainer*>(renderer)->rootElement()) {
-                    if (containsCyclicReference(shadowRoot))
-                        return true;
-                }
-
-            }
-
-            if (node->hasChildNodes()) {
-                if (containsCyclicReference(node))
-                    return true;
-            }
-        }
-    
-        return false;
-    }
+    static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform);
+
+    bool containsCyclicReference(const Node* startNode) const;
+
+private:
+    friend class SVGResourcesCache;
+
+    // FIXME: No-ops for now, until follow-up patch on bug 43031 lands.
+    void addClient(RenderObject*) { }
+    void removeClient(RenderObject*) { }
 
 private:
     AtomicString m_id;
diff --git a/WebCore/rendering/SVGResources.cpp b/WebCore/rendering/SVGResources.cpp
new file mode 100644
index 0000000..de23ce1
--- /dev/null
+++ b/WebCore/rendering/SVGResources.cpp
@@ -0,0 +1,360 @@
+/*
+    Copyright (C) Research In Motion Limited 2010. 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
+    aint 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 "SVGResources.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "SVGPaint.h"
+#include "SVGRenderStyle.h"
+#include "SVGURIReference.h"
+
+namespace WebCore {
+
+SVGResources::SVGResources()
+    : m_clipper(0)
+#if ENABLE(FILTERS)
+    , m_filter(0)
+#endif
+    , m_markerStart(0)
+    , m_markerMid(0)
+    , m_markerEnd(0)
+    , m_masker(0)
+    , m_fill(0)
+    , m_stroke(0)
+{
+}
+
+static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document* document, SVGPaint* paint, AtomicString& id, bool& hasPendingResource)
+{
+    ASSERT(paint);
+
+    SVGPaint::SVGPaintType paintType = paint->paintType();
+    if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR)
+        return 0;
+
+    id = SVGURIReference::getTarget(paint->uri());
+    if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id))
+        return container;
+
+    hasPendingResource = true;
+    return 0;
+}
+
+static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, Node* node)
+{
+    ASSERT(node);
+    if (!node->isSVGElement())
+        return;
+
+    SVGElement* svgElement = static_cast<SVGElement*>(node);
+    if (!svgElement->isStyled())
+        return;
+
+    extensions->addPendingResource(id, static_cast<SVGStyledElement*>(svgElement));
+}
+
+bool SVGResources::buildCachedResources(const RenderObject* object, const SVGRenderStyle* style)
+{
+    ASSERT(object);
+    ASSERT(style);
+
+    Node* node = object->node();
+    ASSERT(node);
+
+    Document* document = object->document();
+    ASSERT(document);
+
+    SVGDocumentExtensions* extensions = document->accessSVGExtensions();
+    ASSERT(extensions);
+
+    bool foundResources = false;
+    if (style->hasClipper()) {
+        AtomicString id(style->clipperResource());
+        m_clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(document, id);
+        if (m_clipper)
+            foundResources = true;
+        else
+            registerPendingResource(extensions, id, node);
+    }
+
+    if (style->hasMasker()) {
+        AtomicString id(style->maskerResource());
+        m_masker = getRenderSVGResourceById<RenderSVGResourceMasker>(document, id);
+        if (m_masker)
+            foundResources = true;
+        else
+            registerPendingResource(extensions, id, node);
+    }
+
+#if ENABLE(FILTERS)
+    if (style->hasFilter()) {
+        AtomicString id(style->filterResource());
+        m_filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document, id);
+        if (m_filter)
+            foundResources = true;
+        else
+            registerPendingResource(extensions, id, node);
+    }
+#endif
+
+    if (style->hasMarkers()) {
+        AtomicString markerStartId(style->markerStartResource());
+        m_markerStart = getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerStartId);
+        if (m_markerStart)
+            foundResources = true;
+        else
+            registerPendingResource(extensions, markerStartId, node);
+
+        AtomicString markerMidId(style->markerMidResource());
+        m_markerMid = getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerMidId);
+        if (m_markerMid)
+            foundResources = true;
+        else
+            registerPendingResource(extensions, markerMidId, node);
+
+        AtomicString markerEndId(style->markerEndResource());
+        m_markerEnd = getRenderSVGResourceById<RenderSVGResourceMarker>(document, markerEndId);
+        if (m_markerEnd)
+            foundResources = true;
+        else
+            registerPendingResource(extensions, markerEndId, node);
+    }
+
+    if (style->hasFill()) {
+        bool hasPendingResource = false;
+        AtomicString id;
+        m_fill = paintingResourceFromSVGPaint(document, style->fillPaint(), id, hasPendingResource);
+        if (m_fill)
+            foundResources = true;
+        else if (hasPendingResource)
+            registerPendingResource(extensions, id, node);
+    }
+
+    if (style->hasStroke()) {
+        bool hasPendingResource = false;
+        AtomicString id;
+        m_stroke = paintingResourceFromSVGPaint(document, style->strokePaint(), id, hasPendingResource);
+        if (m_stroke)
+            foundResources = true;
+        else if (hasPendingResource)
+            registerPendingResource(extensions, id, node);
+    }
+
+    return foundResources;
+}
+
+void SVGResources::invalidateClient(RenderObject* object) const
+{
+    // Ordinary resources
+    if (m_clipper)
+        m_clipper->invalidateClient(object);
+#if ENABLE(FILTERS)
+    if (m_filter)
+        m_filter->invalidateClient(object);
+#endif
+    if (m_masker)
+        m_masker->invalidateClient(object);
+    if (m_markerStart)
+        m_markerStart->invalidateClient(object);
+    if (m_markerMid)
+        m_markerMid->invalidateClient(object);
+    if (m_markerEnd)
+        m_markerEnd->invalidateClient(object);
+
+    // Paint servers
+    if (m_fill)
+        m_fill->invalidateClient(object);
+    if (m_stroke)
+        m_stroke->invalidateClient(object);
+}
+
+void SVGResources::resourceDestroyed(RenderSVGResourceContainer* resource)
+{
+    ASSERT(resource);
+
+    switch (resource->resourceType()) {
+    case MaskerResourceType:
+        if (m_masker == resource) {
+            m_masker->invalidateClients();
+            m_masker = 0;
+        }
+        break;
+    case MarkerResourceType:
+        if (m_markerStart == resource) {
+            m_markerStart->invalidateClients();
+            m_markerStart = 0;
+        }
+
+        if (m_markerMid == resource) {
+            m_markerMid->invalidateClients();
+            m_markerMid = 0;
+        }
+
+        if (m_markerEnd == resource) {
+            m_markerEnd->invalidateClients();
+            m_markerEnd = 0;
+        }
+        break;
+    case PatternResourceType:
+    case LinearGradientResourceType:
+    case RadialGradientResourceType:
+        if (m_fill == resource) {
+            m_fill->invalidateClients();
+            m_fill = 0;
+        }
+
+        if (m_stroke == resource) {
+            m_stroke->invalidateClients();
+            m_stroke = 0;
+        }
+        break;
+#if ENABLE(FILTERS)
+    case FilterResourceType:
+        if (m_filter == resource) {
+            m_filter->invalidateClients();
+            m_filter = 0;
+        }
+        break;
+#endif
+    case ClipperResourceType:
+        if (m_clipper == resource) {
+            m_clipper->invalidateClients();
+            m_clipper = 0;
+        }
+        break;
+    case SolidColorResourceType:
+        ASSERT_NOT_REACHED();
+    }
+}
+
+void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set)
+{
+    // Ordinary resources
+    if (m_clipper)
+        set.add(m_clipper);
+#if ENABLE(FILTERS)
+    if (m_filter)
+        set.add(m_filter);
+#endif
+    if (m_markerStart)
+        set.add(m_markerStart);
+    if (m_markerMid)
+        set.add(m_markerMid);
+    if (m_markerEnd)
+        set.add(m_markerEnd);
+    if (m_masker)
+        set.add(m_masker);
+
+    // Paint servers 
+    if (m_fill)
+        set.add(m_fill);
+    if (m_stroke)
+        set.add(m_stroke);
+}
+
+void SVGResources::resetClipper()
+{
+    ASSERT(m_clipper);
+    m_clipper = 0;
+}
+
+#if ENABLE(FILTERS)
+void SVGResources::resetFilter()
+{
+    ASSERT(m_filter);
+    m_filter = 0;
+}
+#endif
+
+void SVGResources::resetMarkerStart()
+{
+    ASSERT(m_markerStart);
+    m_markerStart = 0;
+}
+
+void SVGResources::resetMarkerMid()
+{
+    ASSERT(m_markerMid);
+    m_markerMid = 0;
+}
+
+void SVGResources::resetMarkerEnd()
+{
+    ASSERT(m_markerEnd);
+    m_markerEnd = 0;
+}
+
+void SVGResources::resetMasker()
+{
+    ASSERT(m_masker);
+    m_masker = 0;
+}
+
+void SVGResources::resetFill()
+{
+    ASSERT(m_fill);
+    m_fill = 0;
+}
+
+void SVGResources::resetStroke()
+{
+    ASSERT(m_stroke);
+    m_stroke = 0;
+}
+
+#ifndef NDEBUG
+void SVGResources::dump(const RenderObject* object)
+{
+    ASSERT(object);
+    ASSERT(object->node());
+
+    fprintf(stderr, "-> this=%p, SVGResources(renderer=%p, node=%p)\n", this, object, object->node());
+    fprintf(stderr, " | DOM Tree:\n");
+    object->node()->showTreeForThis();
+
+    fprintf(stderr, "\n | List of resources:\n");
+    if (m_clipper)
+        fprintf(stderr, " |-> Clipper    : %p (node=%p)\n", m_clipper, m_clipper->node());
+#if ENABLE(FILTERS)
+    if (m_filter)
+        fprintf(stderr, " |-> Filter     : %p (node=%p)\n", m_filter, m_filter->node());
+#endif
+    if (m_markerStart)
+        fprintf(stderr, " |-> MarkerStart: %p (node=%p)\n", m_markerStart, m_markerStart->node());
+    if (m_markerMid)
+        fprintf(stderr, " |-> MarkerMid  : %p (node=%p)\n", m_markerMid, m_markerMid->node());
+    if (m_markerEnd)
+        fprintf(stderr, " |-> MarkerEnd  : %p (node=%p)\n", m_markerEnd, m_markerEnd->node());
+    if (m_masker)
+        fprintf(stderr, " |-> Masker     : %p (node=%p)\n", m_masker, m_masker->node());
+    if (m_fill)
+        fprintf(stderr, " |-> Fill       : %p (node=%p)\n", m_fill, m_fill->node());
+    if (m_stroke)
+        fprintf(stderr, " |-> Stroke     : %p (node=%p)\n", m_stroke, m_stroke->node());
+}
+#endif
+
+}
+
+#endif
diff --git a/WebCore/rendering/SVGResources.h b/WebCore/rendering/SVGResources.h
new file mode 100644
index 0000000..57a4140
--- /dev/null
+++ b/WebCore/rendering/SVGResources.h
@@ -0,0 +1,103 @@
+/*
+    Copyright (C) Research In Motion Limited 2010. 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
+    aint 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 SVGResources_h
+#define SVGResources_h
+
+#if ENABLE(SVG)
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class Document;
+class RenderObject;
+class RenderSVGResourceClipper;
+class RenderSVGResourceContainer;
+class RenderSVGResourceFilter;
+class RenderSVGResourceMarker;
+class RenderSVGResourceMasker;
+class SVGRenderStyle;
+
+// Holds a set of resources associated with a RenderObject
+class SVGResources {
+public:
+    SVGResources();
+
+    bool buildCachedResources(const RenderObject*, const SVGRenderStyle*);
+
+    // Ordinary resources
+    RenderSVGResourceClipper* clipper() const { return m_clipper; }
+#if ENABLE(FILTERS)
+    RenderSVGResourceFilter* filter() const { return m_filter; }
+#endif
+    RenderSVGResourceMarker* markerStart() const { return m_markerStart; }
+    RenderSVGResourceMarker* markerMid() const { return m_markerMid; }
+    RenderSVGResourceMarker* markerEnd() const { return m_markerEnd; }
+    RenderSVGResourceMasker* masker() const { return m_masker; }
+
+    // Paint servers
+    RenderSVGResourceContainer* fill() const { return m_fill; }
+    RenderSVGResourceContainer* stroke() const { return m_stroke; }
+
+    void buildSetOfResources(HashSet<RenderSVGResourceContainer*>&);
+
+    // Methods operating on all cached resources
+    void invalidateClient(RenderObject*) const;
+    void resourceDestroyed(RenderSVGResourceContainer*);
+
+#ifndef NDEBUG
+    void dump(const RenderObject*);
+#endif
+
+private:
+    friend class SVGResourcesCycleSolver;
+
+    // Only used by SVGResourcesCache cycle detection logic
+    void resetClipper();
+#if ENABLE(FILTERS)
+    void resetFilter();
+#endif
+    void resetMarkerStart();
+    void resetMarkerMid();
+    void resetMarkerEnd();
+    void resetMasker();
+    void resetFill();
+    void resetStroke();
+
+private:
+    // Ordinary resources
+    RenderSVGResourceClipper* m_clipper;
+#if ENABLE(FILTERS)
+    RenderSVGResourceFilter* m_filter;
+#endif
+    RenderSVGResourceMarker* m_markerStart;
+    RenderSVGResourceMarker* m_markerMid;
+    RenderSVGResourceMarker* m_markerEnd;
+    RenderSVGResourceMasker* m_masker;
+
+    // Paint servers
+    RenderSVGResourceContainer* m_fill;
+    RenderSVGResourceContainer* m_stroke;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/rendering/SVGResourcesCache.cpp b/WebCore/rendering/SVGResourcesCache.cpp
new file mode 100644
index 0000000..46586cc
--- /dev/null
+++ b/WebCore/rendering/SVGResourcesCache.cpp
@@ -0,0 +1,179 @@
+/*
+    Copyright (C) Research In Motion Limited 2010. 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
+    aint 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 "SVGResourcesCache.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGResourceContainer.h"
+#include "SVGDocumentExtensions.h"
+#include "SVGResources.h"
+#include "SVGResourcesCycleSolver.h"
+
+namespace WebCore {
+
+SVGResourcesCache::SVGResourcesCache()
+{
+}
+
+SVGResourcesCache::~SVGResourcesCache()
+{
+    if (m_cache.isEmpty())
+        return;
+
+    deleteAllValues(m_cache);
+    m_cache.clear();
+}
+
+void SVGResourcesCache::addResourcesFromRenderObject(RenderObject* object, const RenderStyle* style)
+{
+    ASSERT(object);
+    ASSERT(style);
+    ASSERT(!m_cache.contains(object));
+
+    const SVGRenderStyle* svgStyle = style->svgStyle();
+    ASSERT(svgStyle);
+
+    // Build a list of all resources associated with the passed RenderObject
+    SVGResources* resources = new SVGResources;
+    if (!resources->buildCachedResources(object, svgStyle)) {
+        delete resources;
+        return;
+    }
+
+    // Put object in cache.
+    m_cache.set(object, resources);
+
+    // Run cycle-detection _afterwards_, so self-references can be caught as well.
+    SVGResourcesCycleSolver solver(object, resources);
+    solver.resolveCycles();
+
+    // Walk resources and register the render object at each resources.
+    HashSet<RenderSVGResourceContainer*> resourceSet;
+    resources->buildSetOfResources(resourceSet);
+
+    HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
+    for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it)
+        (*it)->addClient(object);
+}
+
+void SVGResourcesCache::removeResourcesFromRenderObject(RenderObject* object)
+{
+    if (!m_cache.contains(object))
+        return;
+
+    SVGResources* resources = m_cache.get(object);
+
+    // Walk resources and register the render object at each resources.
+    HashSet<RenderSVGResourceContainer*> resourceSet;
+    resources->buildSetOfResources(resourceSet);
+
+    HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
+    for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it)
+        (*it)->removeClient(object);
+
+    delete m_cache.take(object);
+}
+
+static inline SVGResourcesCache* resourcesCacheFromRenderObject(RenderObject* renderer)
+{
+    Document* document = renderer->document();
+    ASSERT(document);
+
+    SVGDocumentExtensions* extensions = document->accessSVGExtensions();
+    ASSERT(extensions);
+
+    SVGResourcesCache* cache = extensions->resourcesCache();
+    ASSERT(cache);
+
+    return cache;
+}
+
+SVGResources* SVGResourcesCache::cachedResourcesForRenderObject(RenderObject* renderer)
+{
+    ASSERT(renderer);
+    SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
+    if (!cache->m_cache.contains(renderer))
+        return 0;
+
+    return cache->m_cache.get(renderer);
+}
+
+void SVGResourcesCache::clientLayoutChanged(RenderObject* object)
+{
+    SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object);
+    if (!resources)
+        return;
+
+    resources->invalidateClient(object);
+}
+
+void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifference diff, const RenderStyle* newStyle)
+{
+    ASSERT(renderer);
+    if (diff == StyleDifferenceEqual)
+        return;
+
+    clientUpdatedFromElement(renderer, newStyle);
+
+    // Invalidate resources in ancestor chain, if needed.
+    RenderObject* parent = renderer->parent();
+    while (parent) {
+        if (parent->isSVGResourceContainer()) {
+            parent->toRenderSVGResourceContainer()->invalidateClients();
+            break;
+        }
+
+        parent = parent->parent();
+    }
+}
+ 
+void SVGResourcesCache::clientUpdatedFromElement(RenderObject* renderer, const RenderStyle* newStyle)
+{
+    ASSERT(renderer);
+    ASSERT(renderer->parent());
+
+    SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
+    cache->removeResourcesFromRenderObject(renderer);
+    cache->addResourcesFromRenderObject(renderer, newStyle);
+}
+
+void SVGResourcesCache::clientDestroyed(RenderObject* renderer)
+{
+    ASSERT(renderer);
+    SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer);
+    cache->removeResourcesFromRenderObject(renderer);
+}
+
+void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer* resource)
+{
+    ASSERT(resource);
+    SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource);
+
+    // The resource itself may have clients, that need to be notified.
+    cache->removeResourcesFromRenderObject(resource);
+
+    HashMap<RenderObject*, SVGResources*>::iterator end = cache->m_cache.end();
+    for (HashMap<RenderObject*, SVGResources*>::iterator it = cache->m_cache.begin(); it != end; ++it)
+        it->second->resourceDestroyed(resource);
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/SVGResourcesCache.h b/WebCore/rendering/SVGResourcesCache.h
new file mode 100644
index 0000000..4a61570
--- /dev/null
+++ b/WebCore/rendering/SVGResourcesCache.h
@@ -0,0 +1,65 @@
+/*
+    Copyright (C) Research In Motion Limited 2010. 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
+    aint 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 SVGResourcesCache_h
+#define SVGResourcesCache_h
+
+#if ENABLE(SVG)
+#include "RenderStyleConstants.h"
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderStyle;
+class RenderSVGResourceContainer;
+class SVGResources;
+
+class SVGResourcesCache : public Noncopyable {
+public:
+    SVGResourcesCache();
+    ~SVGResourcesCache();
+
+    void addResourcesFromRenderObject(RenderObject*, const RenderStyle*);
+    void removeResourcesFromRenderObject(RenderObject*);
+    static SVGResources* cachedResourcesForRenderObject(RenderObject*);
+
+    // Called from all SVG renderers destroy() methods - except for RenderSVGResourceContainer.
+    static void clientDestroyed(RenderObject*);
+
+    // Called from all SVG renderers layout() methods.
+    static void clientLayoutChanged(RenderObject*);
+
+    // Called from all SVG renderers styleDidChange() methods.
+    static void clientStyleChanged(RenderObject*, StyleDifference, const RenderStyle* newStyle);
+
+    // Called from all SVG renderers updateFromElement() methods.
+    static void clientUpdatedFromElement(RenderObject*, const RenderStyle* newStyle);
+
+    // Called from RenderSVGResourceContainer::destroy().
+    static void resourceDestroyed(RenderSVGResourceContainer*);
+
+private:
+    HashMap<RenderObject*, SVGResources*> m_cache;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/rendering/SVGResourcesCycleSolver.cpp b/WebCore/rendering/SVGResourcesCycleSolver.cpp
new file mode 100644
index 0000000..838758b
--- /dev/null
+++ b/WebCore/rendering/SVGResourcesCycleSolver.cpp
@@ -0,0 +1,296 @@
+/*
+    Copyright (C) Research In Motion Limited 2010. 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
+    aint 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 "SVGResourcesCycleSolver.h"
+
+// Set to a value > 0, to debug the resource cache.
+#define DEBUG_CYCLE_DETECTION 0
+
+#if ENABLE(SVG)
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "SVGFilterElement.h"
+#include "SVGGradientElement.h"
+#include "SVGPatternElement.h"
+#include "SVGResources.h"
+#include "SVGResourcesCache.h"
+
+namespace WebCore {
+
+SVGResourcesCycleSolver::SVGResourcesCycleSolver(RenderObject* renderer, SVGResources* resources)
+    : m_renderer(renderer)
+    , m_resources(resources)
+{
+    ASSERT(m_renderer);
+    ASSERT(m_resources);
+}
+
+SVGResourcesCycleSolver::~SVGResourcesCycleSolver()
+{
+}
+
+bool SVGResourcesCycleSolver::resourceContainsCycles(RenderObject* renderer) const
+{
+    ASSERT(renderer);
+
+    // First operate on the resources of the given renderer.
+    // <marker id="a"> <path marker-start="url(#b)"/> ...
+    // <marker id="b" marker-start="url(#a)"/>
+    if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer)) {
+        HashSet<RenderSVGResourceContainer*> resourceSet;
+        resources->buildSetOfResources(resourceSet);
+
+        // Walk all resources and check wheter they reference any resource contained in the resources set.
+        HashSet<RenderSVGResourceContainer*>::iterator end = resourceSet.end();
+        for (HashSet<RenderSVGResourceContainer*>::iterator it = resourceSet.begin(); it != end; ++it) {
+            if (m_allResources.contains(*it))
+                return true;
+        }
+    }
+
+    // Then operate on the child resources of the given renderer.
+    // <marker id="a"> <path marker-start="url(#b)"/> ...
+    // <marker id="b"> <path marker-start="url(#a)"/> ...
+    for (RenderObject* child = renderer->firstChild(); child; child = child->nextSibling()) {
+        SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child);
+        if (!childResources)
+            continue;
+        
+        // A child of the given 'resource' contains resources. 
+        HashSet<RenderSVGResourceContainer*> childSet;
+        childResources->buildSetOfResources(childSet);
+
+        // Walk all child resources and check wheter they reference any resource contained in the resources set.
+        HashSet<RenderSVGResourceContainer*>::iterator end = childSet.end();
+        for (HashSet<RenderSVGResourceContainer*>::iterator it = childSet.begin(); it != end; ++it) {
+            if (m_allResources.contains(*it))
+                return true;
+        }
+
+        // Walk children recursively, stop immediately if we found a cycle
+        if (resourceContainsCycles(child))
+            return true;
+    }
+
+    return false;
+}
+
+static inline String targetReferenceFromResource(SVGElement* element, bool& isValid)
+{
+    String target;
+    if (element->hasTagName(SVGNames::patternTag))
+        target = static_cast<SVGPatternElement*>(element)->href();
+    else if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag))
+        target = static_cast<SVGGradientElement*>(element)->href();
+    else if (element->hasTagName(SVGNames::filterTag))
+        target = static_cast<SVGFilterElement*>(element)->href();
+    else {
+        isValid = false;
+        return target;
+    }
+
+    return SVGURIReference::getTarget(target);
+}
+
+static inline void setFollowLinkForChainableResource(SVGElement*, bool)
+{
+    // FIXME: Enable once the follow-up patch for bug 43031 lands
+}
+
+bool SVGResourcesCycleSolver::chainableResourceContainsCycles(RenderSVGResourceContainer* container) const
+{
+    ASSERT(container);
+    ASSERT(container->node());
+    ASSERT(container->node()->isSVGElement());
+
+    // Chainable resources cycle detection is performed in the DOM tree.
+    SVGElement* element = static_cast<SVGElement*>(container->node());
+    ASSERT(element);
+
+    HashSet<SVGElement*> processedObjects;
+
+    bool isValid = true;
+    String target = targetReferenceFromResource(element, isValid);
+    ASSERT(isValid);
+
+    SVGElement* previousElement = element;
+    while (!target.isEmpty()) {
+        Node* targetNode = element->document()->getElementById(target);
+        if (!targetNode || !targetNode->isSVGElement())
+            break;
+
+        // Catch cylic chaining, otherwhise we'll run into an infinite loop here.
+        // <pattern id="foo" xlink:href="#bar"/> <pattern id="bar xlink:href="#foo"/>
+        SVGElement* targetElement = static_cast<SVGElement*>(targetNode);
+
+        bool followLink = true;
+        if (processedObjects.contains(targetElement) || targetElement == element)
+            followLink = false;
+
+        setFollowLinkForChainableResource(previousElement, followLink);
+        if (!followLink)
+            return false;
+
+        previousElement = targetElement;
+        processedObjects.add(targetElement);
+        target = targetReferenceFromResource(targetElement, isValid);
+        if (!isValid)
+            break;
+    }
+
+    // Couldn't find any direct cycle in the xlink:href chain, maybe there's an indirect one.
+    // <pattern id="foo" xlink:href="#bar"/> <pattern id="bar"> <rect fill="url(#foo)"...
+    HashSet<SVGElement*>::iterator end = processedObjects.end();
+    for (HashSet<SVGElement*>::iterator it = processedObjects.begin(); it != end; ++it) {
+        RenderObject* renderer = (*it)->renderer();
+        if (!renderer)
+            continue;
+        ASSERT(renderer->isSVGResourceContainer());
+        if (m_allResources.contains(renderer->toRenderSVGResourceContainer()))
+            return true;
+    }
+
+    return false;
+}
+
+void SVGResourcesCycleSolver::resolveCycles()
+{
+    ASSERT(m_allResources.isEmpty());
+
+#if DEBUG_CYCLE_DETECTION > 0
+    fprintf(stderr, "\nBefore cycle detection:\n");
+    m_resources->dump(m_renderer);
+#endif
+
+    // Stash all resources into a HashSet for the ease of traversing.
+    HashSet<RenderSVGResourceContainer*> localResources;
+    m_resources->buildSetOfResources(localResources);
+    ASSERT(!localResources.isEmpty());
+
+    // Add all parent resource containers to the HashSet.
+    HashSet<RenderSVGResourceContainer*> parentResources;
+    RenderObject* parent = m_renderer->parent();
+    while (parent) {
+        if (parent->isSVGResourceContainer())
+            parentResources.add(parent->toRenderSVGResourceContainer());
+        parent = parent->parent();
+    }
+
+#if DEBUG_CYCLE_DETECTION > 0
+    fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n");
+    {
+        fprintf(stderr, "Local resources:\n");
+        HashSet<RenderSVGResourceContainer*>::iterator end = localResources.end();
+        for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it)
+            fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node());
+
+        fprintf(stderr, "Parent resources:\n");
+        end = parentResources.end();
+        for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it)
+            fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node());
+    }
+#endif
+
+    // Build combined set of local and parent resources.
+    m_allResources = localResources;
+    HashSet<RenderSVGResourceContainer*>::iterator end = parentResources.end();
+    for (HashSet<RenderSVGResourceContainer*>::iterator it = parentResources.begin(); it != end; ++it)
+        m_allResources.add(*it);
+
+    ASSERT(!m_allResources.isEmpty());
+
+    // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer'
+    // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it.
+    end = localResources.end();
+    for (HashSet<RenderSVGResourceContainer*>::iterator it = localResources.begin(); it != end; ++it) {
+        RenderSVGResourceContainer* resource = *it;
+
+        // Special handling for resources that can be chained using xlink:href - need to detect cycles as well!
+        switch (resource->resourceType()) {
+        case PatternResourceType:
+        case LinearGradientResourceType:
+        case RadialGradientResourceType:
+        case FilterResourceType:
+            if (chainableResourceContainsCycles(resource)) {
+                breakCycle(resource);
+                continue;
+            }
+            break;
+        default:
+            break;
+        }
+
+        if (parentResources.contains(resource) || resourceContainsCycles(resource))
+            breakCycle(resource);
+    }
+
+#if DEBUG_CYCLE_DETECTION > 0
+    fprintf(stderr, "\nAfter cycle detection:\n");
+    m_resources->dump(m_renderer);
+#endif
+
+    m_allResources.clear();
+}
+
+void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer* resourceLeadingToCycle)
+{
+    ASSERT(resourceLeadingToCycle);
+    switch (resourceLeadingToCycle->resourceType()) {
+    case MaskerResourceType:
+        ASSERT(resourceLeadingToCycle == m_resources->masker());
+        m_resources->resetMasker();
+        break;
+    case MarkerResourceType:
+        ASSERT(resourceLeadingToCycle == m_resources->markerStart() || resourceLeadingToCycle == m_resources->markerMid() || resourceLeadingToCycle == m_resources->markerEnd());
+        if (m_resources->markerStart() == resourceLeadingToCycle)
+            m_resources->resetMarkerStart();
+        if (m_resources->markerMid() == resourceLeadingToCycle)
+            m_resources->resetMarkerMid();
+        if (m_resources->markerEnd() == resourceLeadingToCycle)
+            m_resources->resetMarkerEnd();
+        break;
+    case PatternResourceType:
+    case LinearGradientResourceType:
+    case RadialGradientResourceType:
+        ASSERT(resourceLeadingToCycle == m_resources->fill() || resourceLeadingToCycle == m_resources->stroke());
+        if (m_resources->fill() == resourceLeadingToCycle)
+            m_resources->resetFill();
+        if (m_resources->stroke() == resourceLeadingToCycle)
+            m_resources->resetStroke();
+        break;
+    case FilterResourceType:
+        ASSERT(resourceLeadingToCycle == m_resources->filter());
+        m_resources->resetFilter();
+        break;
+    case ClipperResourceType:
+        ASSERT(resourceLeadingToCycle == m_resources->clipper());
+        m_resources->resetClipper();
+        break;
+    case SolidColorResourceType:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
+}
+
+#endif
diff --git a/WebCore/rendering/SVGResourcesCycleSolver.h b/WebCore/rendering/SVGResourcesCycleSolver.h
new file mode 100644
index 0000000..1f49354
--- /dev/null
+++ b/WebCore/rendering/SVGResourcesCycleSolver.h
@@ -0,0 +1,52 @@
+/*
+    Copyright (C) Research In Motion Limited 2010. 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
+    aint 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 SVGResourcesCycleSolver_h
+#define SVGResourcesCycleSolver_h
+
+#if ENABLE(SVG)
+#include <wtf/HashSet.h>
+
+namespace WebCore {
+
+class RenderObject;
+class RenderSVGResourceContainer;
+class SVGResources;
+
+class SVGResourcesCycleSolver : public Noncopyable {
+public:
+    SVGResourcesCycleSolver(RenderObject*, SVGResources*);
+    ~SVGResourcesCycleSolver();
+
+    void resolveCycles();
+
+private:
+    bool resourceContainsCycles(RenderObject*) const;
+    bool chainableResourceContainsCycles(RenderSVGResourceContainer*) const;
+    void breakCycle(RenderSVGResourceContainer*);
+
+    RenderObject* m_renderer;
+    SVGResources* m_resources;
+    HashSet<RenderSVGResourceContainer*> m_allResources; 
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/svg/SVGDocumentExtensions.cpp b/WebCore/svg/SVGDocumentExtensions.cpp
index bc4d6e8..325bcc7 100644
--- a/WebCore/svg/SVGDocumentExtensions.cpp
+++ b/WebCore/svg/SVGDocumentExtensions.cpp
@@ -34,16 +34,17 @@
 #include "Frame.h"
 #include "FrameLoader.h"
 #include "Page.h"
+#include "SMILTimeContainer.h"
 #include "SVGSMILElement.h"
 #include "SVGSVGElement.h"
-#include "SMILTimeContainer.h"
-#include "ScriptableDocumentParser.h"
 #include "ScriptController.h"
+#include "ScriptableDocumentParser.h"
 
 namespace WebCore {
 
 SVGDocumentExtensions::SVGDocumentExtensions(Document* doc)
     : m_doc(doc)
+    , m_resourcesCache(new SVGResourcesCache)
 {
 }
 
diff --git a/WebCore/svg/SVGDocumentExtensions.h b/WebCore/svg/SVGDocumentExtensions.h
index d31536c..bfe48d1 100644
--- a/WebCore/svg/SVGDocumentExtensions.h
+++ b/WebCore/svg/SVGDocumentExtensions.h
@@ -25,6 +25,7 @@
 
 #if ENABLE(SVG)
 #include "AtomicStringHash.h"
+#include "SVGResourcesCache.h"
 #include "StringImpl.h"
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
@@ -59,11 +60,14 @@ public:
     void reportWarning(const String&);
     void reportError(const String&);
 
+    SVGResourcesCache* resourcesCache() const { return m_resourcesCache.get(); }
+
 private:
     Document* m_doc; // weak reference
     HashSet<SVGSVGElement*> m_timeContainers; // For SVG 1.2 support this will need to be made more general.
     HashMap<AtomicString, RenderSVGResourceContainer*> m_resources;
     HashMap<AtomicString, HashSet<SVGStyledElement*>*> m_pendingResources;
+    OwnPtr<SVGResourcesCache> m_resourcesCache;
 
     SVGDocumentExtensions(const SVGDocumentExtensions&);
     SVGDocumentExtensions& operator=(const SVGDocumentExtensions&);

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list