CSS url() filters with forward references don't work
https://bugs.webkit.org/show_bug.cgi?id=90405

Based on a patch by Keyar Hood.

Reviewed by Dirk Schulze.

Source/WebCore:

In order for CSS to reference SVG filters that will occur later in
the document, or will be added at a future time, we need a way to
notify the target element (the one the filter style is applied to)
when the correct SVG filter is added to the DOM.
There is already code for SVG elements that handles this problem, in
SVGResourcesCache. This patch allows any element to have a reference to
an SVG element in SVGResourceCache.

Tests: css3/filters/effect-reference-after.html
       css3/filters/effect-reference-delete-crash.html
       css3/filters/effect-reference-delete.html
       css3/filters/effect-reference-rename.html
       css3/filters/effect-reference-reset-style-delete-crash.html
       svg/filters/filter-cycle.html

* dom/Element.cpp:
(WebCore::Element::hasPendingResources): Added
(WebCore::Element::setHasPendingResources): Added
(WebCore::Element::clearHasPendingResources): Added
* dom/Element.h:
Accessors for ElementRareData's new bit flag.
(WebCore::Element::buildPendingResource):
Virtual function to override for referenced elements (moved from SVGElement).
* dom/ElementRareData.h:
(WebCore::ElementRareData::ElementRareData):
Add a new bit flag to indicate whether the element depends on pending resources or not.
* platform/graphics/texmap/TextureMapperImageBuffer.cpp:
(WebCore::BitmapTextureImageBuffer::applyFilters):
Changed to the new function signature for FilterEffectRenderer::build().
* rendering/FilterEffectRenderer.cpp:
(WebCore::FilterEffectRenderer::buildReferenceFilter):
Changed signature to accept a RenderObject rather than a Document, so we know which node to notify when the SVG filter arrives.  If the referenced filter cannot be found, add its id as a pending reference.
(WebCore::FilterEffectRenderer::build):
Changed signature to accept a RenderObject rather than a Document, so we know which node to notify when the SVG filter arrives.
* rendering/FilterEffectRenderer.h:
Change to signatures of build() and buildReferenceFilter() to pass
a RenderObject instead of a Document.
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::updateOrRemoveFilterEffectRenderer):
Use the new semantics for FilterEffectRenderer::build().
* rendering/RenderObject.cpp:
(WebCore::RenderObject::willBeDestroyed):
Notify the cache if a RenderObject is destroyed.
* rendering/svg/RenderSVGResourceContainer.cpp:
(WebCore::RenderSVGResourceContainer::registerResource):
Call clearHasPendingResourceIfPossible on the SVGDocumentExtensions, not
on the element, since we want to support generic Elements.
* rendering/svg/SVGResources.cpp:
(WebCore::SVGResources::buildCachedResources):
Add support for building filters on non-SVG elements.
* rendering/svg/SVGResourcesCache.cpp:
(WebCore::SVGResourcesCache::addResourcesFromRenderObject):
Do cycle detection only on SVG elements.
(WebCore::SVGResourcesCache::clientStyleChanged):
For non-SVG elements, set a synthetic style change when parent resources
are invalidated.
(WebCore::SVGResourcesCache::resourceDestroyed):
Add support for non-SVG Elements.
* svg/SVGDocumentExtensions.cpp:
(WebCore::SVGDocumentExtensions::addPendingResource):
(WebCore::SVGDocumentExtensions::isElementPendingResources):
(WebCore::SVGDocumentExtensions::isElementPendingResource):
(WebCore::SVGDocumentExtensions::removeElementFromPendingResources):
(WebCore::SVGDocumentExtensions::removeElementFromPendingResourcesForRemoval):
Changed to allow use of Element instead of SVGElement.
(WebCore::SVGDocumentExtensions::clearHasPendingResourcesIfPossible):
Moved from SVGElement, and made to work on any Element.  This way,
we avoid adding this function to Element itself.
* svg/SVGDocumentExtensions.h:
SVGElement -> Element.
* svg/SVGElement.cpp:
* svg/SVGElement.h:
All functions moved to Element, except for clearHasPendingResourcesIfPossible() moved to SVGDocumentExtensions.
* svg/SVGElementRareData.h:
(WebCore::SVGElementRareData::SVGElementRareData):
m_hasPendingResources add accessors moved to ElementRareData.
* svg/SVGStyledElement.cpp:
(WebCore::SVGStyledElement::buildPendingResourcesIfNeeded):
SVGElement -> Element, and call SVGDocumentExtensions for
clearHasPendingResourcesIfPossible().

LayoutTests:

* css3/filters/effect-reference-after-expected.txt: Added.
* css3/filters/effect-reference-after.html: Added.
* css3/filters/effect-reference-delete-crash-expected.txt: Added.
* css3/filters/effect-reference-delete-crash.html: Added.
* css3/filters/effect-reference-delete-expected.txt: Added.
* css3/filters/effect-reference-delete.html: Added.
* css3/filters/effect-reference-rename-expected.txt: Added.
* css3/filters/effect-reference-rename.html: Added.
* css3/filters/effect-reference-reset-style-delete-crash-expected.txt: Added.
* css3/filters/effect-reference-reset-style-delete-crash.html: Added.
* css3/filters/script-tests/effect-reference-delete-crash.js: Added.
* css3/filters/script-tests/effect-reference-reset-style-delete-crash.js: Added.
* svg/filters/filter-cycle.html: Added.
* svg/filters/filter-cycle-expected.html: Added.
* platform/chromium-linux/css3/filters/effect-reference-after-expected: Added.
* platform/chromium-linux/css3/filters/effect-reference-delete-expected.png: Added.
* platform/chromium-linux/css3/filters/effect-reference-rename-expected.png: Added.
* platform/chromium/TestExpectations:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@136975 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 32ebc39..c36a7b2 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,31 @@
+2012-12-07  Stephen White  <senorblanco@chromium.org>
+
+        CSS url() filters with forward references don't work
+        https://bugs.webkit.org/show_bug.cgi?id=90405
+
+        Based on a patch by Keyar Hood.
+
+        Reviewed by Dirk Schulze.
+
+        * css3/filters/effect-reference-after-expected.txt: Added.
+        * css3/filters/effect-reference-after.html: Added.
+        * css3/filters/effect-reference-delete-crash-expected.txt: Added.
+        * css3/filters/effect-reference-delete-crash.html: Added.
+        * css3/filters/effect-reference-delete-expected.txt: Added.
+        * css3/filters/effect-reference-delete.html: Added.
+        * css3/filters/effect-reference-rename-expected.txt: Added.
+        * css3/filters/effect-reference-rename.html: Added.
+        * css3/filters/effect-reference-reset-style-delete-crash-expected.txt: Added.
+        * css3/filters/effect-reference-reset-style-delete-crash.html: Added.
+        * css3/filters/script-tests/effect-reference-delete-crash.js: Added.
+        * css3/filters/script-tests/effect-reference-reset-style-delete-crash.js: Added.
+        * svg/filters/filter-cycle.html: Added.
+        * svg/filters/filter-cycle-expected.html: Added.
+        * platform/chromium-linux/css3/filters/effect-reference-after-expected: Added.
+        * platform/chromium-linux/css3/filters/effect-reference-delete-expected.png: Added.
+        * platform/chromium-linux/css3/filters/effect-reference-rename-expected.png: Added.
+        * platform/chromium/TestExpectations:
+
 2012-12-07  Alexis Menard  <alexis@webkit.org>
 
         Unreviewed EFL gardening.
diff --git a/LayoutTests/css3/filters/effect-reference-after-expected.txt b/LayoutTests/css3/filters/effect-reference-after-expected.txt
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-after-expected.txt
@@ -0,0 +1 @@
+ 
diff --git a/LayoutTests/css3/filters/effect-reference-after.html b/LayoutTests/css3/filters/effect-reference-after.html
new file mode 100644
index 0000000..2bf7aea
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-after.html
@@ -0,0 +1,25 @@
+<html>
+  <head>
+    <style>
+      img {
+        margin: 10px;
+      }
+    </style>
+    <script type="application/x-javascript">
+      function draw() {
+          if (window.testRunner)
+            testRunner.dumpAsText(true);
+      }
+    </script>
+  </head>
+  <body onload="draw();">
+    <img style="-webkit-filter: url(#MyFilter); filter: url(#MyFilter);" src="resources/reference.png">
+    <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
+      <defs>
+        <filter id="MyFilter">
+          <feColorMatrix type="hueRotate" values="180"/>
+        </filter>
+      </defs>
+    </svg>
+  </body>
+</html>
diff --git a/LayoutTests/css3/filters/effect-reference-delete-crash-expected.txt b/LayoutTests/css3/filters/effect-reference-delete-crash-expected.txt
new file mode 100644
index 0000000..cfa0071
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-delete-crash-expected.txt
@@ -0,0 +1,9 @@
+Test that no crash occurs when a SVG filter is deleted that was referenced by a deleted HTML element.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/css3/filters/effect-reference-delete-crash.html b/LayoutTests/css3/filters/effect-reference-delete-crash.html
new file mode 100644
index 0000000..388ab72
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-delete-crash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+  <img id="html" style="-webkit-filter: url(#MyFilter); filter: url(#MyFilter);" src="resources/reference.png">
+  <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1" id="svg">
+    <defs>
+      <filter id="MyFilter">
+        <feColorMatrix type="hueRotate" values="180"/>
+      </filter>
+    </defs>
+  </svg>
+  <script src="script-tests/effect-reference-delete-crash.js"></script>
+  <script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/css3/filters/effect-reference-delete-expected.txt b/LayoutTests/css3/filters/effect-reference-delete-expected.txt
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-delete-expected.txt
@@ -0,0 +1 @@
+ 
diff --git a/LayoutTests/css3/filters/effect-reference-delete.html b/LayoutTests/css3/filters/effect-reference-delete.html
new file mode 100644
index 0000000..25beb51
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-delete.html
@@ -0,0 +1,31 @@
+<html>
+  <head>
+    <style>
+    img {
+        margin: 10px;
+    }
+    </style>
+
+    <script type="application/x-javascript">
+      function draw() {
+          if (window.testRunner)
+              testRunner.dumpAsText(true);
+
+          svg = document.getElementById("svg");
+          svg.parentNode.removeChild(svg);
+      }
+    </script>
+  </head>
+  <body onload="draw();">
+    <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
+      <defs>
+        <filter id="MyFilter">
+          <feColorMatrix type="hueRotate" values="180"/>
+        </filter>
+      </defs>
+    </svg>
+
+    <img style="-webkit-filter: url(#MyFilter); filter: url(#MyFilter);" src="resources/reference.png">
+  </body>
+</html>
+
diff --git a/LayoutTests/css3/filters/effect-reference-rename-expected.txt b/LayoutTests/css3/filters/effect-reference-rename-expected.txt
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-rename-expected.txt
@@ -0,0 +1 @@
+ 
diff --git a/LayoutTests/css3/filters/effect-reference-rename.html b/LayoutTests/css3/filters/effect-reference-rename.html
new file mode 100644
index 0000000..c36aefa
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-rename.html
@@ -0,0 +1,28 @@
+<html>
+  <head>
+    <style>
+      img {
+        margin: 10px;
+      }
+    </style>
+    <script type="application/x-javascript">
+      function draw() {
+          if (window.testRunner)
+            testRunner.dumpAsText(true);
+      }
+    </script>
+  </head>
+  <body onload="draw();">
+    <img style="-webkit-filter: url(#MyFilter); filter: url(#MyFilter);" src="resources/reference.png">
+    <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1">
+      <defs>
+        <filter id="NotMyFilter">
+          <feColorMatrix type="hueRotate" values="180"/>
+        </filter>
+      </defs>
+    </svg>
+  </body>
+</html>
+<script>
+document.getElementById("NotMyFilter").id = "MyFilter";
+</script>
diff --git a/LayoutTests/css3/filters/effect-reference-reset-style-delete-crash-expected.txt b/LayoutTests/css3/filters/effect-reference-reset-style-delete-crash-expected.txt
new file mode 100644
index 0000000..cfa0071
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-reset-style-delete-crash-expected.txt
@@ -0,0 +1,9 @@
+Test that no crash occurs when a SVG filter is deleted that was referenced by a deleted HTML element.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/css3/filters/effect-reference-reset-style-delete-crash.html b/LayoutTests/css3/filters/effect-reference-reset-style-delete-crash.html
new file mode 100644
index 0000000..388ab72
--- /dev/null
+++ b/LayoutTests/css3/filters/effect-reference-reset-style-delete-crash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+  <img id="html" style="-webkit-filter: url(#MyFilter); filter: url(#MyFilter);" src="resources/reference.png">
+  <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" version="1.1" id="svg">
+    <defs>
+      <filter id="MyFilter">
+        <feColorMatrix type="hueRotate" values="180"/>
+      </filter>
+    </defs>
+  </svg>
+  <script src="script-tests/effect-reference-delete-crash.js"></script>
+  <script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/css3/filters/script-tests/effect-reference-delete-crash.js b/LayoutTests/css3/filters/script-tests/effect-reference-delete-crash.js
new file mode 100644
index 0000000..94ff5d9
--- /dev/null
+++ b/LayoutTests/css3/filters/script-tests/effect-reference-delete-crash.js
@@ -0,0 +1,8 @@
+description("Test that no crash occurs when a SVG filter is deleted that was referenced by a deleted HTML element.");
+
+html = document.getElementById('html');
+html.parentNode.removeChild(html);
+svg = document.getElementById('svg');
+svg.parentNode.removeChild(svg);
+
+successfullyParsed = true;
diff --git a/LayoutTests/css3/filters/script-tests/effect-reference-reset-style-delete-crash.js b/LayoutTests/css3/filters/script-tests/effect-reference-reset-style-delete-crash.js
new file mode 100644
index 0000000..cf750d2
--- /dev/null
+++ b/LayoutTests/css3/filters/script-tests/effect-reference-reset-style-delete-crash.js
@@ -0,0 +1,8 @@
+description("Test that no crash occurs when a SVG filter is deleted that used to be referenced by an HTML element but is no longer.");
+
+html = document.getElementById('html');
+html.style = "";
+svg = document.getElementById('svg');
+svg.parentNode.removeChild(svg);
+
+successfullyParsed = true;
diff --git a/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-after-expected.png b/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-after-expected.png
new file mode 100644
index 0000000..ef8d477
--- /dev/null
+++ b/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-after-expected.png
Binary files differ
diff --git a/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-delete-expected.png b/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-delete-expected.png
new file mode 100644
index 0000000..e3a4a36
--- /dev/null
+++ b/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-delete-expected.png
Binary files differ
diff --git a/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-rename-expected.png b/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-rename-expected.png
new file mode 100644
index 0000000..ef8d477
--- /dev/null
+++ b/LayoutTests/platform/chromium-linux/css3/filters/effect-reference-rename-expected.png
Binary files differ
diff --git a/LayoutTests/platform/chromium/TestExpectations b/LayoutTests/platform/chromium/TestExpectations
index a6f57d1..a3f5ea5 100644
--- a/LayoutTests/platform/chromium/TestExpectations
+++ b/LayoutTests/platform/chromium/TestExpectations
@@ -3659,6 +3659,11 @@
 
 webkit.org/b/92941 accessibility/loading-iframe-updates-axtree.html [ Crash Pass ]
 
+# Tests added by bug 90405. Need rebaselining for platforms other than linux.
+webkit.org/b/93149 css3/filters/effect-reference-after.html [ ImageOnlyFailure Missing ]
+webkit.org/b/93149 css3/filters/effect-reference-delete.html [ ImageOnlyFailure Missing ]
+webkit.org/b/93149 css3/filters/effect-reference-rename.html [ ImageOnlyFailure Missing ]
+
 # Tests added by bug 76270. According to bug 92968, they should be skipped in Chromium.
 webkit.org/b/92968 http/tests/appcache/abort-cache-onchecking-manifest-404.html
 webkit.org/b/92968 http/tests/appcache/abort-cache-onchecking-resource-404.html
diff --git a/LayoutTests/svg/filters/filter-cycle-expected.html b/LayoutTests/svg/filters/filter-cycle-expected.html
new file mode 100644
index 0000000..8ce1313
--- /dev/null
+++ b/LayoutTests/svg/filters/filter-cycle-expected.html
@@ -0,0 +1,5 @@
+<html>
+  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100">
+    <rect x="0" y="0" width="100" height="100" fill="rgb(0,255,0)"/>
+  </svg>
+</html>
diff --git a/LayoutTests/svg/filters/filter-cycle.html b/LayoutTests/svg/filters/filter-cycle.html
new file mode 100644
index 0000000..4826a46
--- /dev/null
+++ b/LayoutTests/svg/filters/filter-cycle.html
@@ -0,0 +1,10 @@
+<html>
+  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100">
+    <defs>
+      <filter id="filter1" xlink:href="url(#filter1)">
+        <feOffset/>
+      </filter>
+    </defs>
+    <rect x="0" y="0" width="100" height="100" fill="rgb(0,255,0)" style="filter:url(#filter1);"/>
+  </svg>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 62e8189..bfe809c 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,93 @@
+2012-12-07  Stephen White  <senorblanco@chromium.org>
+
+        CSS url() filters with forward references don't work
+        https://bugs.webkit.org/show_bug.cgi?id=90405
+
+        Based on a patch by Keyar Hood.
+
+        Reviewed by Dirk Schulze.
+
+        In order for CSS to reference SVG filters that will occur later in
+        the document, or will be added at a future time, we need a way to
+        notify the target element (the one the filter style is applied to)
+        when the correct SVG filter is added to the DOM.
+        There is already code for SVG elements that handles this problem, in
+        SVGResourcesCache. This patch allows any element to have a reference to
+        an SVG element in SVGResourceCache.
+
+        Tests: css3/filters/effect-reference-after.html
+               css3/filters/effect-reference-delete-crash.html
+               css3/filters/effect-reference-delete.html
+               css3/filters/effect-reference-rename.html
+               css3/filters/effect-reference-reset-style-delete-crash.html
+               svg/filters/filter-cycle.html
+
+        * dom/Element.cpp:
+        (WebCore::Element::hasPendingResources): Added
+        (WebCore::Element::setHasPendingResources): Added
+        (WebCore::Element::clearHasPendingResources): Added
+        * dom/Element.h:
+        Accessors for ElementRareData's new bit flag.
+        (WebCore::Element::buildPendingResource):
+        Virtual function to override for referenced elements (moved from SVGElement).
+        * dom/ElementRareData.h:
+        (WebCore::ElementRareData::ElementRareData):
+        Add a new bit flag to indicate whether the element depends on pending resources or not.
+        * platform/graphics/texmap/TextureMapperImageBuffer.cpp:
+        (WebCore::BitmapTextureImageBuffer::applyFilters):
+        Changed to the new function signature for FilterEffectRenderer::build().
+        * rendering/FilterEffectRenderer.cpp:
+        (WebCore::FilterEffectRenderer::buildReferenceFilter):
+        Changed signature to accept a RenderObject rather than a Document, so we know which node to notify when the SVG filter arrives.  If the referenced filter cannot be found, add its id as a pending reference.
+        (WebCore::FilterEffectRenderer::build):
+        Changed signature to accept a RenderObject rather than a Document, so we know which node to notify when the SVG filter arrives.
+        * rendering/FilterEffectRenderer.h:
+        Change to signatures of build() and buildReferenceFilter() to pass
+        a RenderObject instead of a Document.
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::updateOrRemoveFilterEffectRenderer):
+        Use the new semantics for FilterEffectRenderer::build().
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::willBeDestroyed):
+        Notify the cache if a RenderObject is destroyed.
+        * rendering/svg/RenderSVGResourceContainer.cpp:
+        (WebCore::RenderSVGResourceContainer::registerResource):
+        Call clearHasPendingResourceIfPossible on the SVGDocumentExtensions, not
+        on the element, since we want to support generic Elements.
+        * rendering/svg/SVGResources.cpp:
+        (WebCore::SVGResources::buildCachedResources):
+        Add support for building filters on non-SVG elements.
+        * rendering/svg/SVGResourcesCache.cpp:
+        (WebCore::SVGResourcesCache::addResourcesFromRenderObject):
+        Do cycle detection only on SVG elements.
+        (WebCore::SVGResourcesCache::clientStyleChanged):
+        For non-SVG elements, set a synthetic style change when parent resources
+        are invalidated.
+        (WebCore::SVGResourcesCache::resourceDestroyed):
+        Add support for non-SVG Elements.
+        * svg/SVGDocumentExtensions.cpp:
+        (WebCore::SVGDocumentExtensions::addPendingResource):
+        (WebCore::SVGDocumentExtensions::isElementPendingResources):
+        (WebCore::SVGDocumentExtensions::isElementPendingResource):
+        (WebCore::SVGDocumentExtensions::removeElementFromPendingResources):
+        (WebCore::SVGDocumentExtensions::removeElementFromPendingResourcesForRemoval):
+        Changed to allow use of Element instead of SVGElement.
+        (WebCore::SVGDocumentExtensions::clearHasPendingResourcesIfPossible):
+        Moved from SVGElement, and made to work on any Element.  This way,
+        we avoid adding this function to Element itself.
+        * svg/SVGDocumentExtensions.h:
+        SVGElement -> Element.
+        * svg/SVGElement.cpp:
+        * svg/SVGElement.h:
+        All functions moved to Element, except for clearHasPendingResourcesIfPossible() moved to SVGDocumentExtensions.
+        * svg/SVGElementRareData.h:
+        (WebCore::SVGElementRareData::SVGElementRareData):
+        m_hasPendingResources add accessors moved to ElementRareData.
+        * svg/SVGStyledElement.cpp:
+        (WebCore::SVGStyledElement::buildPendingResourcesIfNeeded):
+        SVGElement -> Element, and call SVGDocumentExtensions for
+        clearHasPendingResourcesIfPossible().
+
 2012-12-07  Eberhard Graether  <egraether@google.com>
 
         Web Inspector: Add shortcut to set visibility:hidden on elements in the ElementsPanel
diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp
index 287bd80..627e981 100644
--- a/Source/WebCore/dom/Element.cpp
+++ b/Source/WebCore/dom/Element.cpp
@@ -2693,4 +2693,21 @@
     info.addMember(m_attributeData);
 }
 
+#if ENABLE(SVG)
+bool Element::hasPendingResources() const
+{
+    return hasRareData() && elementRareData()->hasPendingResources();
+}
+
+void Element::setHasPendingResources()
+{
+    ensureElementRareData()->setHasPendingResources(true);
+}
+
+void Element::clearHasPendingResources()
+{
+    ensureElementRareData()->setHasPendingResources(false);
+}
+#endif
+
 } // namespace WebCore
diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h
index 829c513..c032405f 100644
--- a/Source/WebCore/dom/Element.h
+++ b/Source/WebCore/dom/Element.h
@@ -427,6 +427,10 @@
 
 #if ENABLE(SVG)
     virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const;
+    bool hasPendingResources() const;
+    void setHasPendingResources();
+    void clearHasPendingResources();
+    virtual void buildPendingResource() { };
 #endif
     
 #if ENABLE(FULLSCREEN_API)
diff --git a/Source/WebCore/dom/ElementRareData.h b/Source/WebCore/dom/ElementRareData.h
index 7905cb5..c0040b4 100644
--- a/Source/WebCore/dom/ElementRareData.h
+++ b/Source/WebCore/dom/ElementRareData.h
@@ -106,6 +106,9 @@
     IntSize savedLayerScrollOffset() const { return m_savedLayerScrollOffset; }
     void setSavedLayerScrollOffset(IntSize size) { m_savedLayerScrollOffset = size; }
 
+    bool hasPendingResources() const { return m_hasPendingResources; }
+    void setHasPendingResources(bool has) { m_hasPendingResources = has; }
+
 private:
     // Many fields are in NodeRareData for better packing.
     LayoutSize m_minimumSizeForResizing;
@@ -121,6 +124,9 @@
 
     IntSize m_savedLayerScrollOffset;
 
+#if ENABLE(SVG)
+    bool m_hasPendingResources : 1;
+#endif
 private:
     void releasePseudoElement(PseudoElement*);
 };
@@ -135,6 +141,9 @@
     , m_minimumSizeForResizing(defaultMinimumSizeForResizing())
     , m_generatedBefore(0)
     , m_generatedAfter(0)
+#if ENABLE(SVG)
+    , m_hasPendingResources(false)
+#endif
 {
 }
 
diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp
index 48540c4..557cd32 100644
--- a/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp
+++ b/Source/WebCore/platform/graphics/texmap/TextureMapperImageBuffer.cpp
@@ -148,8 +148,8 @@
     RefPtr<FilterEffectRenderer> renderer = FilterEffectRenderer::create();
     renderer->setSourceImageRect(FloatRect(FloatPoint::zero(), contentTexture.size()));
 
-    // The document parameter is only needed for CSS shaders.
-    renderer->build(0 /*document */, filters);
+    // The renderer parameter is only needed for CSS shaders and reference filters.
+    renderer->build(0 /*renderer */, filters);
     renderer->allocateBackingStoreIfNeeded();
     GraphicsContext* context = renderer->inputContext();
     context->drawImageBuffer(static_cast<const BitmapTextureImageBuffer&>(contentTexture).m_image.get(), ColorSpaceDeviceRGB, IntPoint::zero());
diff --git a/Source/WebCore/rendering/FilterEffectRenderer.cpp b/Source/WebCore/rendering/FilterEffectRenderer.cpp
index e53d338..871aa98 100644
--- a/Source/WebCore/rendering/FilterEffectRenderer.cpp
+++ b/Source/WebCore/rendering/FilterEffectRenderer.cpp
@@ -88,6 +88,9 @@
 #if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
 static PassRefPtr<FECustomFilter> createCustomFilterEffect(Filter* filter, Document* document, ValidatedCustomFilterOperation* operation)
 {
+    if (!document)
+        return 0;
+
     CustomFilterGlobalContext* globalContext = document->renderView()->customFilterGlobalContext();
     globalContext->prepareContextIfNeeded(document->view()->hostWindow());
     if (!globalContext->context())
@@ -122,9 +125,15 @@
     return sourceImage() ? sourceImage()->context() : 0;
 }
 
-PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(Document* document, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation)
+PassRefPtr<FilterEffect> FilterEffectRenderer::buildReferenceFilter(RenderObject* renderer, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation* filterOperation)
 {
 #if ENABLE(SVG)
+    if (!renderer)
+        return 0;
+
+    Document* document = renderer->document();
+    ASSERT(document);
+
     CachedSVGDocumentReference* cachedSVGDocumentReference = filterOperation->cachedSVGDocumentReference();
     CachedSVGDocument* cachedSVGDocument = cachedSVGDocumentReference ? cachedSVGDocumentReference->document() : 0;
 
@@ -137,8 +146,12 @@
         return 0;
 
     Element* filter = document->getElementById(filterOperation->fragment());
-    if (!filter)
+    if (!filter) {
+        // Although we did not find the referenced filter, it might exist later
+        // in the document
+        document->accessSVGExtensions()->addPendingResource(filterOperation->fragment(), toElement(renderer->node()));
         return 0;
+    }
 
     RefPtr<FilterEffect> effect;
 
@@ -176,12 +189,8 @@
 #endif
 }
 
-bool FilterEffectRenderer::build(Document* document, const FilterOperations& operations)
+bool FilterEffectRenderer::build(RenderObject* renderer, const FilterOperations& operations)
 {
-#if !ENABLE(CSS_SHADERS) || !USE(3D_GRAPHICS)
-    UNUSED_PARAM(document);
-#endif
-
 #if ENABLE(CSS_SHADERS)
     m_hasCustomShaderFilter = false;
 #endif
@@ -201,7 +210,7 @@
         switch (filterOperation->getOperationType()) {
         case FilterOperation::REFERENCE: {
             ReferenceFilterOperation* referenceOperation = static_cast<ReferenceFilterOperation*>(filterOperation);
-            effect = buildReferenceFilter(document, previousEffect, referenceOperation);
+            effect = buildReferenceFilter(renderer, previousEffect, referenceOperation);
             referenceOperation->setFilterEffect(effect);
             break;
         }
@@ -344,6 +353,7 @@
             break;
         case FilterOperation::VALIDATED_CUSTOM: {
             ValidatedCustomFilterOperation* customFilterOperation = static_cast<ValidatedCustomFilterOperation*>(filterOperation);
+            Document* document = renderer ? renderer->document() : 0;
             effect = createCustomFilterEffect(this, document, customFilterOperation);
             if (effect)
                 m_hasCustomShaderFilter = true;
diff --git a/Source/WebCore/rendering/FilterEffectRenderer.h b/Source/WebCore/rendering/FilterEffectRenderer.h
index f73188f..9602bd8 100644
--- a/Source/WebCore/rendering/FilterEffectRenderer.h
+++ b/Source/WebCore/rendering/FilterEffectRenderer.h
@@ -100,8 +100,8 @@
     GraphicsContext* inputContext();
     ImageBuffer* output() const { return lastEffect()->asImageBuffer(); }
 
-    bool build(Document*, const FilterOperations&);
-    PassRefPtr<FilterEffect> buildReferenceFilter(Document*, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation*);
+    bool build(RenderObject* renderer, const FilterOperations&);
+    PassRefPtr<FilterEffect> buildReferenceFilter(RenderObject* renderer, PassRefPtr<FilterEffect> previousEffect, ReferenceFilterOperation*);
     bool updateBackingStoreRect(const FloatRect& filterRect);
     void allocateBackingStoreIfNeeded();
     void clearIntermediateResults();
diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp
index 84241c5..93ea0c3 100644
--- a/Source/WebCore/rendering/RenderLayer.cpp
+++ b/Source/WebCore/rendering/RenderLayer.cpp
@@ -5406,7 +5406,7 @@
 
     // If the filter fails to build, remove it from the layer. It will still attempt to
     // go through regular processing (e.g. compositing), but never apply anything.
-    if (!filterInfo->renderer()->build(renderer()->document(), computeFilterOperations(renderer()->style())))
+    if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(renderer()->style())))
         filterInfo->setRenderer(0);
 }
 
diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
index 9ffc853..a41f990 100644
--- a/Source/WebCore/rendering/RenderObject.cpp
+++ b/Source/WebCore/rendering/RenderObject.cpp
@@ -81,6 +81,7 @@
 #if ENABLE(SVG)
 #include "RenderSVGResourceContainer.h"
 #include "SVGRenderSupport.h"
+#include "SVGResourcesCache.h"
 #endif
 
 using namespace std;
@@ -2376,6 +2377,10 @@
     }
     animation()->cancelAnimations(this);
 
+#if ENABLE(SVG)
+    SVGResourcesCache::clientDestroyed(this);
+#endif
+
     remove();
 
     // Continuation and first-letter can generate several renderers associated with a single node.
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
index e311c1c..f0cda75 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp
@@ -184,7 +184,7 @@
     const SVGDocumentExtensions::SVGPendingElements::const_iterator end = clients->end();
     for (SVGDocumentExtensions::SVGPendingElements::const_iterator it = clients->begin(); it != end; ++it) {
         ASSERT((*it)->hasPendingResources());
-        (*it)->clearHasPendingResourcesIfPossible();
+        extensions->clearHasPendingResourcesIfPossible(*it);
         RenderObject* renderer = (*it)->renderer();
         if (!renderer)
             continue;
diff --git a/Source/WebCore/rendering/svg/SVGResources.cpp b/Source/WebCore/rendering/svg/SVGResources.cpp
index d909740..9ba3c57 100644
--- a/Source/WebCore/rendering/svg/SVGResources.cpp
+++ b/Source/WebCore/rendering/svg/SVGResources.cpp
@@ -190,6 +190,17 @@
 
     Node* node = object->node();
     ASSERT(node);
+    if (!node->isSVGElement()) {
+        Document* document = object->document();
+        ASSERT(document);
+
+        if (!style->hasFilter())
+            return false;
+
+        AtomicString id(style->filterResource());
+        return setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id));
+    }
+
     ASSERT(node->isSVGElement());
 
     SVGElement* element = static_cast<SVGElement*>(node);
diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
index 8b48cf5..73ee232 100644
--- a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
+++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp
@@ -21,7 +21,9 @@
 #include "SVGResourcesCache.h"
 
 #if ENABLE(SVG)
+#include "Element.h"
 #include "HTMLNames.h"
+#include "Node.h"
 #include "RenderSVGResourceContainer.h"
 #include "SVGDocumentExtensions.h"
 #include "SVGResources.h"
@@ -58,6 +60,7 @@
     // Put object in cache.
     m_cache.set(object, resources);
 
+    ASSERT(object->node());
     // Run cycle-detection _afterwards_, so self-references can be caught as well.
     SVGResourcesCycleSolver solver(object, resources);
     solver.resolveCycles();
@@ -143,6 +146,10 @@
     cache->addResourcesFromRenderObject(renderer, newStyle);
 
     RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false);
+
+    ASSERT(renderer->node());
+    if (!renderer->node()->isSVGElement())
+        renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
 }
 
 static inline bool rendererCanHaveResources(RenderObject* renderer)
@@ -202,7 +209,7 @@
 
         // Mark users of destroyed resources as pending resolution based on the id of the old resource.
         Element* resourceElement = toElement(resource->node());
-        SVGStyledElement* clientElement = toSVGStyledElement(it->key->node());
+        Element* clientElement = toElement(it->key->node());
         SVGDocumentExtensions* extensions = clientElement->document()->accessSVGExtensions();
 
         extensions->addPendingResource(resourceElement->fastGetAttribute(HTMLNames::idAttr), clientElement);
diff --git a/Source/WebCore/svg/SVGDocumentExtensions.cpp b/Source/WebCore/svg/SVGDocumentExtensions.cpp
index 889229a..3747ccb 100644
--- a/Source/WebCore/svg/SVGDocumentExtensions.cpp
+++ b/Source/WebCore/svg/SVGDocumentExtensions.cpp
@@ -27,6 +27,7 @@
 #include "Console.h"
 #include "DOMWindow.h"
 #include "Document.h"
+#include "Element.h"
 #include "EventListener.h"
 #include "Frame.h"
 #include "FrameLoader.h"
@@ -148,7 +149,7 @@
     reportMessage(m_document, ErrorMessageLevel, "Error: " + message);
 }
 
-void SVGDocumentExtensions::addPendingResource(const AtomicString& id, SVGElement* element)
+void SVGDocumentExtensions::addPendingResource(const AtomicString& id, Element* element)
 {
     ASSERT(element);
 
@@ -175,7 +176,7 @@
     return m_pendingResources.contains(id);
 }
 
-bool SVGDocumentExtensions::isElementPendingResources(SVGElement* element) const
+bool SVGDocumentExtensions::isElementPendingResources(Element* element) const
 {
     // This algorithm takes time proportional to the number of pending resources and need not.
     // If performance becomes an issue we can keep a counted set of elements and answer the question efficiently.
@@ -193,7 +194,7 @@
     return false;
 }
 
-bool SVGDocumentExtensions::isElementPendingResource(SVGElement* element, const AtomicString& id) const
+bool SVGDocumentExtensions::isElementPendingResource(Element* element, const AtomicString& id) const
 {
     ASSERT(element);
 
@@ -203,7 +204,13 @@
     return m_pendingResources.get(id)->contains(element);
 }
 
-void SVGDocumentExtensions::removeElementFromPendingResources(SVGElement* element)
+void SVGDocumentExtensions::clearHasPendingResourcesIfPossible(Element* element)
+{
+    if (!isElementPendingResources(element))
+        element->clearHasPendingResources();
+}
+
+void SVGDocumentExtensions::removeElementFromPendingResources(Element* element)
 {
     ASSERT(element);
 
@@ -221,7 +228,7 @@
                 toBeRemoved.append(it->key);
         }
 
-        element->clearHasPendingResourcesIfPossible();
+        clearHasPendingResourcesIfPossible(element);
 
         // We use the removePendingResource function here because it deals with set lifetime correctly.
         Vector<AtomicString>::iterator vectorEnd = toBeRemoved.end();
@@ -274,7 +281,7 @@
         m_pendingResourcesForRemoval.add(id, existing);
 }
 
-SVGElement* SVGDocumentExtensions::removeElementFromPendingResourcesForRemoval(const AtomicString& id)
+Element* SVGDocumentExtensions::removeElementFromPendingResourcesForRemoval(const AtomicString& id)
 {
     if (id.isEmpty())
         return 0;
@@ -284,7 +291,7 @@
         return 0;
 
     SVGPendingElements::iterator firstElement = resourceSet->begin();
-    SVGElement* element = *firstElement;
+    Element* element = *firstElement;
 
     resourceSet->remove(firstElement);
 
diff --git a/Source/WebCore/svg/SVGDocumentExtensions.h b/Source/WebCore/svg/SVGDocumentExtensions.h
index 3207d36..7d6b786 100644
--- a/Source/WebCore/svg/SVGDocumentExtensions.h
+++ b/Source/WebCore/svg/SVGDocumentExtensions.h
@@ -40,11 +40,12 @@
 class SVGResourcesCache;
 class SVGSMILElement;
 class SVGSVGElement;
+class Element;
 
 class SVGDocumentExtensions {
     WTF_MAKE_NONCOPYABLE(SVGDocumentExtensions); WTF_MAKE_FAST_ALLOCATED;
 public:
-    typedef HashSet<SVGElement*> SVGPendingElements;
+    typedef HashSet<Element*> SVGPendingElements;
     SVGDocumentExtensions(Document*);
     ~SVGDocumentExtensions();
     
@@ -91,17 +92,18 @@
 public:
     // This HashMap contains a list of pending resources. Pending resources, are such
     // which are referenced by any object in the SVG document, but do NOT exist yet.
-    // For instance, dynamically built gradients / patterns / clippers...
-    void addPendingResource(const AtomicString& id, SVGElement*);
+    // For instance, dynamically build gradients / patterns / clippers...
+    void addPendingResource(const AtomicString& id, Element*);
     bool hasPendingResource(const AtomicString& id) const;
-    bool isElementPendingResources(SVGElement*) const;
-    bool isElementPendingResource(SVGElement*, const AtomicString& id) const;
-    void removeElementFromPendingResources(SVGElement*);
+    bool isElementPendingResources(Element*) const;
+    bool isElementPendingResource(Element*, const AtomicString& id) const;
+    void clearHasPendingResourcesIfPossible(Element*);
+    void removeElementFromPendingResources(Element*);
     PassOwnPtr<SVGPendingElements> removePendingResource(const AtomicString& id);
 
     // The following two functions are used for scheduling a pending resource to be removed.
     void markPendingResourcesForRemoval(const AtomicString&);
-    SVGElement* removeElementFromPendingResourcesForRemoval(const AtomicString&);
+    Element* removeElementFromPendingResourcesForRemoval(const AtomicString&);
 
 private:
     PassOwnPtr<SVGPendingElements> removePendingResourceForRemoval(const AtomicString&);
diff --git a/Source/WebCore/svg/SVGElement.cpp b/Source/WebCore/svg/SVGElement.cpp
index 442e983..13ef6c0 100644
--- a/Source/WebCore/svg/SVGElement.cpp
+++ b/Source/WebCore/svg/SVGElement.cpp
@@ -544,22 +544,6 @@
         svgAttributeChanged(name);
 }
 
-bool SVGElement::hasPendingResources() const
-{
-    return hasSVGRareData() && svgRareData()->hasPendingResources();
-}
-
-void SVGElement::setHasPendingResources()
-{
-    ensureSVGRareData()->setHasPendingResources(true);
-}
-
-void SVGElement::clearHasPendingResourcesIfPossible()
-{
-    if (!document()->accessSVGExtensions()->isElementPendingResources(this))
-        ensureSVGRareData()->setHasPendingResources(false);
-}
-
 void SVGElement::updateAnimatedSVGAttribute(const QualifiedName& name) const
 {
     if (!attributeData() || !attributeData()->m_animatedSVGAttributesAreDirty)
diff --git a/Source/WebCore/svg/SVGElement.h b/Source/WebCore/svg/SVGElement.h
index 9426b78..54935c0 100644
--- a/Source/WebCore/svg/SVGElement.h
+++ b/Source/WebCore/svg/SVGElement.h
@@ -70,11 +70,6 @@
 
     virtual void svgAttributeChanged(const QualifiedName&) { }
 
-    bool hasPendingResources() const;
-    void setHasPendingResources();
-    void clearHasPendingResourcesIfPossible();
-    virtual void buildPendingResource() { }
-
     virtual void animatedPropertyTypeForAttribute(const QualifiedName&, Vector<AnimatedPropertyType>&);
 
     void sendSVGLoadEventIfPossible(bool sendParentLoadEvents = false);
diff --git a/Source/WebCore/svg/SVGElementRareData.h b/Source/WebCore/svg/SVGElementRareData.h
index 5069485..f5e50f4 100644
--- a/Source/WebCore/svg/SVGElementRareData.h
+++ b/Source/WebCore/svg/SVGElementRareData.h
@@ -41,7 +41,6 @@
         , m_cursorImageValue(0)
         , m_correspondingElement(0)
         , m_instancesUpdatesBlocked(false)
-        , m_hasPendingResources(false)
         , m_useOverrideComputedStyle(false)
         , m_needsOverrideComputedStyleUpdate(false)
     {
@@ -66,9 +65,6 @@
     bool instanceUpdatesBlocked() const { return m_instancesUpdatesBlocked; }
     void setInstanceUpdatesBlocked(bool value) { m_instancesUpdatesBlocked = value; }
 
-    bool hasPendingResources() const { return m_hasPendingResources; }
-    void setHasPendingResources(bool value) { m_hasPendingResources = value; }
-
     SVGCursorElement* cursorElement() const { return m_cursorElement; }
     void setCursorElement(SVGCursorElement* cursorElement) { m_cursorElement = cursorElement; }
 
@@ -115,7 +111,6 @@
     CSSCursorImageValue* m_cursorImageValue;
     SVGElement* m_correspondingElement;
     bool m_instancesUpdatesBlocked : 1;
-    bool m_hasPendingResources : 1;
     bool m_useOverrideComputedStyle : 1;
     bool m_needsOverrideComputedStyleUpdate : 1;
     RefPtr<StylePropertySet> m_animatedSMILStyleProperties;
diff --git a/Source/WebCore/svg/SVGStyledElement.cpp b/Source/WebCore/svg/SVGStyledElement.cpp
index 47f0342..989a028 100644
--- a/Source/WebCore/svg/SVGStyledElement.cpp
+++ b/Source/WebCore/svg/SVGStyledElement.cpp
@@ -367,11 +367,11 @@
     extensions->markPendingResourcesForRemoval(resourceId);
 
     // Rebuild pending resources for each client of a pending resource that is being removed.
-    while (SVGElement* clientElement = extensions->removeElementFromPendingResourcesForRemoval(resourceId)) {
+    while (Element* clientElement = extensions->removeElementFromPendingResourcesForRemoval(resourceId)) {
         ASSERT(clientElement->hasPendingResources());
         if (clientElement->hasPendingResources()) {
             clientElement->buildPendingResource();
-            clientElement->clearHasPendingResourcesIfPossible();
+            extensions->clearHasPendingResourcesIfPossible(clientElement);
         }
     }
 }