[CSS Shaders] Implement a StyleCustomFilterProgram cache
authorachicu@adobe.com <achicu@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Mar 2013 22:17:44 +0000 (22:17 +0000)
committerachicu@adobe.com <achicu@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Mar 2013 22:17:44 +0000 (22:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=112602

Reviewed by Dean Jackson.

Source/WebCore:

When the style is recalculated, the new computed RenderStyle is saved as the m_style of the
RenderObject, even if the style was not different.

In the case of Custom Filters, a new StyleCustomFilterProgram was created at all times, but the
actual equality check was done by comparing the pair of cached shaders from inside the StyleCustomFilterProgram.

Because of that the RenderLayer::styleChanged was not called when the new StyleCustomFilterProgram was created, so it
will end up still knowing only about the previous StyleCustomFilterProgram.

The RenderLayer sets itself as a client of the StyleCustomFilterProgram, so that it can repaint itself
when the program is loaded, but because RenderLayer::styleChanged is not called, it will not add itself as a client of the new
StyleCustomFilterProgram.

StyleCustomFilterProgram waits until the first client to load the programs, so in this case it will just remain unloaded.

There was no crash, but just an assert in debug mode. Also, as a visible side-effect some frames were rendered using blank shaders,
resulting in a pass-through filter.

The fix would be to actually make the RenderStyle::diff detect the change of the StyleCustomFilterProgram
using the pointer value and not the values. However, that will always invalidate the "filter" property because
of the StyleCustomFilterProgram that always gets created during the recalculation time.

I've added StyleCustomFilterProgramCache to cache all the instances of the StyleCustomFilterPrograms that a
StyleResolver allocates. This way, next time it will try to reuse previously allocated StyleCustomFilterPrograms.
The key of the cache is the CustomFilterProgramInfo, that combines the URLs to the shaders and a couple of other program settings.

StyleCustomFilterProgramCache is owned by the StyleResovler and StyleCustomFilterPrograms are responsible with
removing themselves from the cache when the last reference goes away.

This change makes the previous "platform level" program cache obsolete and I will remove that in a future patch.
https://bugs.webkit.org/show_bug.cgi?id=112844

Test: css3/filters/custom/custom-filter-reload.html

* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* css/StyleResolver.cpp:
(WebCore::StyleResolver::lookupCustomFilterProgram): Lookup any similar programs in the cache. It will create a new pending
StyleCustomFilterProgram if there is no pre-cached version of the program.
if no program is found. loadPendingShaders is responsible for adding the program in the cache if it is actually going to be used.
(WebCore::StyleResolver::loadPendingShaders): At this point the program is final, so it's safe to add it to the cache.
(WebCore::StyleResolver::createCustomFilterOperationWithInlineSyntax):
* css/StyleResolver.h:
(StyleResolver):
* css/WebKitCSSShaderValue.cpp:
(WebCore::WebKitCSSShaderValue::completeURL): Factored out the function to compute the complete URL of the resource.
(WebCore::WebKitCSSShaderValue::cachedShader):
* css/WebKitCSSShaderValue.h:
(WebCore::toWebKitCSSShaderValue):
(WebKitCSSShaderValue):
* platform/graphics/filters/CustomFilterOperation.cpp:
(WebCore::CustomFilterOperation::blend):
* platform/graphics/filters/CustomFilterOperation.h:
(WebCore::CustomFilterOperation::operator==): Removed. Programs should now compare by pointer. Kept it as
private to catch any potential use of it.
* rendering/style/StyleCustomFilterProgram.cpp: Copied from Source/WebCore/css/WebKitCSSShaderValue.h.
(WebCore::StyleCustomFilterProgram::~StyleCustomFilterProgram): Destructor removes the program from the cache.
* rendering/style/StyleCustomFilterProgram.h:
(WebCore::StyleCustomFilterProgram::setVertexShader): Added an assert to check that the shader is not in the
cache while the mutation happens. Otherwise the cache might have the wrong key.
(WebCore::StyleCustomFilterProgram::setFragmentShader): Ditto.
(WebCore::StyleCustomFilterProgram::isLoaded): Added more asserts to catch cases when the program is used with no clients.
(StyleCustomFilterProgram):
(WebCore::StyleCustomFilterProgram::hasPendingShaders):
(WebCore::StyleCustomFilterProgram::inCache):
(WebCore::StyleCustomFilterProgram::setCache): Function called when a program is added to / removed from the cache.
(WebCore::StyleCustomFilterProgram::vertexShaderURL): Added methods to store the KURL that we used as keys in the cache.
The same KURLs will be used to lookup and remove the filter at the end.
(WebCore::StyleCustomFilterProgram::setVertexShaderURL):
(WebCore::StyleCustomFilterProgram::fragmentShaderURL):
(WebCore::StyleCustomFilterProgram::setFragmentShaderURL):
(WebCore::StyleCustomFilterProgram::StyleCustomFilterProgram):
* rendering/style/StyleCustomFilterProgramCache.cpp: Added.
(WebCore::StyleCustomFilterProgramCache::programCacheKey):
(WebCore::StyleCustomFilterProgramCache::StyleCustomFilterProgramCache):
(WebCore::StyleCustomFilterProgramCache::~StyleCustomFilterProgramCache): Destructor removes itself from all the
referenced StyleCustomFilterPrograms. This is to avoid issues with different destruction orders.
(WebCore::StyleCustomFilterProgramCache::lookup):
(WebCore::StyleCustomFilterProgramCache::add):
(WebCore::StyleCustomFilterProgramCache::remove):
* rendering/style/StyleCustomFilterProgramCache.h:
(StyleCustomFilterProgramCache):
* platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h:
(WebCore::CoordinatedCustomFilterProgram::operator==: Removed. Programs should now compare by pointer.

LayoutTests:

Added a new test to check for the case when the style is recalculated but the
filter property is not changed. All the other cases for the new StyleCustomFilterProgramCache
class should be tested by existing tests.

* css3/filters/custom/custom-filter-reload-expected.txt: Added.
* css3/filters/custom/custom-filter-reload.html: Added.

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

22 files changed:
LayoutTests/ChangeLog
LayoutTests/css3/filters/custom/custom-filter-reload-expected.txt [new file with mode: 0644]
LayoutTests/css3/filters/custom/custom-filter-reload.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/css/WebKitCSSShaderValue.cpp
Source/WebCore/css/WebKitCSSShaderValue.h
Source/WebCore/platform/graphics/filters/CustomFilterOperation.cpp
Source/WebCore/platform/graphics/filters/CustomFilterOperation.h
Source/WebCore/platform/graphics/filters/CustomFilterProgram.cpp
Source/WebCore/platform/graphics/filters/CustomFilterProgram.h
Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h
Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp [new file with mode: 0644]
Source/WebCore/rendering/style/StyleCustomFilterProgram.h
Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp [new file with mode: 0644]
Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h [new file with mode: 0644]

index 4513b23..fe58cb5 100644 (file)
@@ -1,3 +1,17 @@
+2013-03-21  Alexandru Chiculita  <achicu@adobe.com>
+
+        [CSS Shaders] Implement a StyleCustomFilterProgram cache
+        https://bugs.webkit.org/show_bug.cgi?id=112602
+
+        Reviewed by Dean Jackson.
+
+        Added a new test to check for the case when the style is recalculated but the
+        filter property is not changed. All the other cases for the new StyleCustomFilterProgramCache
+        class should be tested by existing tests.
+
+        * css3/filters/custom/custom-filter-reload-expected.txt: Added.
+        * css3/filters/custom/custom-filter-reload.html: Added.
+
 2013-03-21  Jochen Eisinger  <jochen@chromium.org>
 
         Skip triaged crashes on content shell
diff --git a/LayoutTests/css3/filters/custom/custom-filter-reload-expected.txt b/LayoutTests/css3/filters/custom/custom-filter-reload-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/css3/filters/custom/custom-filter-reload.html b/LayoutTests/css3/filters/custom/custom-filter-reload.html
new file mode 100644 (file)
index 0000000..a79d13e
--- /dev/null
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<!-- 
+    This tests verifies that we don't assert when the style is recalculated but the filter property doesn't change.
+-->
+<html>
+<head>
+    <script>
+        if (window.testRunner) {
+            window.testRunner.overridePreference("WebKitCSSCustomFilterEnabled", "1");
+            window.testRunner.overridePreference("WebKitWebGLEnabled", "1");
+            window.testRunner.dumpAsText();
+            window.testRunner.waitUntilDone();
+        }
+
+        function test()
+        {
+            // Force a layout.
+            document.body.clientHeight;
+            var boxes = document.querySelectorAll(".box");
+            for (var i = 0; i < boxes.length; ++i)
+                boxes[i].classList.add("trigger-style-recalc");
+            
+            // Switch the parent to composited mode, so that we can trigger 
+            // a rebuild of the compositing layer tree.
+            document.body.style.webkitTransform = "translateZ(0px)"
+
+            // Force a layout.
+            document.body.clientHeight;
+
+            // If we get this far with no assert, the test passed.
+            if (window.testRunner)
+                window.testRunner.notifyDone();
+        }
+    </script>
+    <style>
+        .box {
+            height: 50px;
+            width: 50px;
+            background-color: green;
+            -webkit-transform: translateZ(0);
+        }
+
+        .vertex_shader
+        {
+            -webkit-filter: custom(url('../resources/vertex-offset.vs'));
+        }
+
+        .fragment_shader
+        {
+            -webkit-filter: custom(none mix(url('../resources/color-offset.fs') normal source-atop));
+        }
+
+        .both_shaders
+        {
+            -webkit-filter: custom(url('../resources/vertex-offset.vs') mix(url('../resources/color-offset.fs') normal source-atop));
+        }
+
+        .trigger-style-recalc {
+            /* No change, we just need a new style recalculation. */
+        }
+    </style>
+</head>
+
+<body onload="test()">
+    <!-- 
+        You should see three green boxes. Last two boxes have a different shade of green. Last box is slightly bigger on the left side.
+        The test passes if there is no crash or assert.
+    -->
+
+    <div class="box vertex_shader"></div>
+    <div class="box both_shaders"></div>
+    <div class="box fragment_shader"></div>
+
+</body>
+</html>
index baf6fb4..f9f65ab 100644 (file)
@@ -1,3 +1,98 @@
+2013-03-21  Alexandru Chiculita  <achicu@adobe.com>
+
+        [CSS Shaders] Implement a StyleCustomFilterProgram cache
+        https://bugs.webkit.org/show_bug.cgi?id=112602
+
+        Reviewed by Dean Jackson.
+
+        When the style is recalculated, the new computed RenderStyle is saved as the m_style of the
+        RenderObject, even if the style was not different.
+
+        In the case of Custom Filters, a new StyleCustomFilterProgram was created at all times, but the
+        actual equality check was done by comparing the pair of cached shaders from inside the StyleCustomFilterProgram.
+
+        Because of that the RenderLayer::styleChanged was not called when the new StyleCustomFilterProgram was created, so it
+        will end up still knowing only about the previous StyleCustomFilterProgram.
+
+        The RenderLayer sets itself as a client of the StyleCustomFilterProgram, so that it can repaint itself
+        when the program is loaded, but because RenderLayer::styleChanged is not called, it will not add itself as a client of the new
+        StyleCustomFilterProgram.
+
+        StyleCustomFilterProgram waits until the first client to load the programs, so in this case it will just remain unloaded.
+
+        There was no crash, but just an assert in debug mode. Also, as a visible side-effect some frames were rendered using blank shaders, 
+        resulting in a pass-through filter.
+
+        The fix would be to actually make the RenderStyle::diff detect the change of the StyleCustomFilterProgram
+        using the pointer value and not the values. However, that will always invalidate the "filter" property because
+        of the StyleCustomFilterProgram that always gets created during the recalculation time.
+
+        I've added StyleCustomFilterProgramCache to cache all the instances of the StyleCustomFilterPrograms that a
+        StyleResolver allocates. This way, next time it will try to reuse previously allocated StyleCustomFilterPrograms. 
+        The key of the cache is the CustomFilterProgramInfo, that combines the URLs to the shaders and a couple of other program settings.
+
+        StyleCustomFilterProgramCache is owned by the StyleResovler and StyleCustomFilterPrograms are responsible with
+        removing themselves from the cache when the last reference goes away.
+
+        This change makes the previous "platform level" program cache obsolete and I will remove that in a future patch.
+        https://bugs.webkit.org/show_bug.cgi?id=112844
+
+        Test: css3/filters/custom/custom-filter-reload.html
+
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::lookupCustomFilterProgram): Lookup any similar programs in the cache. It will create a new pending 
+        StyleCustomFilterProgram if there is no pre-cached version of the program.
+        if no program is found. loadPendingShaders is responsible for adding the program in the cache if it is actually going to be used.
+        (WebCore::StyleResolver::loadPendingShaders): At this point the program is final, so it's safe to add it to the cache.
+        (WebCore::StyleResolver::createCustomFilterOperationWithInlineSyntax):
+        * css/StyleResolver.h:
+        (StyleResolver):
+        * css/WebKitCSSShaderValue.cpp:
+        (WebCore::WebKitCSSShaderValue::completeURL): Factored out the function to compute the complete URL of the resource.
+        (WebCore::WebKitCSSShaderValue::cachedShader):
+        * css/WebKitCSSShaderValue.h:
+        (WebCore::toWebKitCSSShaderValue):
+        (WebKitCSSShaderValue):
+        * platform/graphics/filters/CustomFilterOperation.cpp:
+        (WebCore::CustomFilterOperation::blend):
+        * platform/graphics/filters/CustomFilterOperation.h:
+        (WebCore::CustomFilterOperation::operator==): Removed. Programs should now compare by pointer. Kept it as
+        private to catch any potential use of it.
+        * rendering/style/StyleCustomFilterProgram.cpp: Copied from Source/WebCore/css/WebKitCSSShaderValue.h.
+        (WebCore::StyleCustomFilterProgram::~StyleCustomFilterProgram): Destructor removes the program from the cache.
+        * rendering/style/StyleCustomFilterProgram.h:
+        (WebCore::StyleCustomFilterProgram::setVertexShader): Added an assert to check that the shader is not in the
+        cache while the mutation happens. Otherwise the cache might have the wrong key.
+        (WebCore::StyleCustomFilterProgram::setFragmentShader): Ditto.
+        (WebCore::StyleCustomFilterProgram::isLoaded): Added more asserts to catch cases when the program is used with no clients.
+        (StyleCustomFilterProgram):
+        (WebCore::StyleCustomFilterProgram::hasPendingShaders):
+        (WebCore::StyleCustomFilterProgram::inCache):
+        (WebCore::StyleCustomFilterProgram::setCache): Function called when a program is added to / removed from the cache.
+        (WebCore::StyleCustomFilterProgram::vertexShaderURL): Added methods to store the KURL that we used as keys in the cache.
+        The same KURLs will be used to lookup and remove the filter at the end.
+        (WebCore::StyleCustomFilterProgram::setVertexShaderURL):
+        (WebCore::StyleCustomFilterProgram::fragmentShaderURL):
+        (WebCore::StyleCustomFilterProgram::setFragmentShaderURL):
+        (WebCore::StyleCustomFilterProgram::StyleCustomFilterProgram):
+        * rendering/style/StyleCustomFilterProgramCache.cpp: Added.
+        (WebCore::StyleCustomFilterProgramCache::programCacheKey):
+        (WebCore::StyleCustomFilterProgramCache::StyleCustomFilterProgramCache):
+        (WebCore::StyleCustomFilterProgramCache::~StyleCustomFilterProgramCache): Destructor removes itself from all the
+        referenced StyleCustomFilterPrograms. This is to avoid issues with different destruction orders.
+        (WebCore::StyleCustomFilterProgramCache::lookup):
+        (WebCore::StyleCustomFilterProgramCache::add):
+        (WebCore::StyleCustomFilterProgramCache::remove):
+        * rendering/style/StyleCustomFilterProgramCache.h:
+        (StyleCustomFilterProgramCache):
+        * platform/graphics/texmap/coordinated/CoordinatedCustomFilterProgram.h:
+        (WebCore::CoordinatedCustomFilterProgram::operator==: Removed. Programs should now compare by pointer.
+
 2013-03-21  Joshua Bell  <jsbell@chromium.org>
 
         IndexedDB: Ensure all API methods have IDB_TRACE macros
index a3a1d2f..b396ddc 100644 (file)
@@ -4663,7 +4663,10 @@ webcore_sources += \
        Source/WebCore/rendering/style/StyleCachedImageSet.h \
        Source/WebCore/rendering/style/StyleCachedShader.cpp \
        Source/WebCore/rendering/style/StyleCachedShader.h \
+       Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp \
        Source/WebCore/rendering/style/StyleCustomFilterProgram.h \
+       Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp \
+       Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h \
        Source/WebCore/rendering/style/StyleDashboardRegion.h \
        Source/WebCore/rendering/style/StyleDeprecatedFlexibleBoxData.cpp \
        Source/WebCore/rendering/style/StyleDeprecatedFlexibleBoxData.h \
index c4b40e9..39d5112 100644 (file)
@@ -1286,6 +1286,8 @@ SOURCES += \
     rendering/style/StyleCachedImage.cpp \
     rendering/style/StyleCachedImageSet.cpp \
     rendering/style/StyleCachedShader.cpp \
+    rendering/style/StyleCustomFilterProgram.cpp \
+    rendering/style/StyleCustomFilterProgramCache.cpp \
     rendering/style/StyleDeprecatedFlexibleBoxData.cpp \
     rendering/style/StyleFilterData.cpp \
     rendering/style/StyleFlexibleBoxData.cpp \
@@ -2583,6 +2585,7 @@ HEADERS += \
     rendering/style/StyleCachedImage.h \
     rendering/style/StyleCachedShader.h \
     rendering/style/StyleCustomFilterProgram.h \
+    rendering/style/StyleCustomFilterProgramCache.h \
     rendering/style/StyleDeprecatedFlexibleBoxData.h \
     rendering/style/StyleFilterData.h \
     rendering/style/StyleFlexibleBoxData.h \
index be10975..e66673b 100644 (file)
             'rendering/style/StyleCachedImageSet.cpp',
             'rendering/style/StyleCachedShader.h',
             'rendering/style/StyleCachedShader.cpp',
+            'rendering/style/StyleCustomFilterProgramCache.cpp',
+            'rendering/style/StyleCustomFilterProgramCache.h',
+            'rendering/style/StyleCustomFilterProgram.cpp',
             'rendering/style/StyleCustomFilterProgram.h',
             'rendering/style/StyleDeprecatedFlexibleBoxData.cpp',
             'rendering/style/StyleFilterData.cpp',
index 8db25f6..e0bf065 100755 (executable)
                                        >
                                </File>
                                <File
+                                       RelativePath="..\rendering\style\StyleCustomFilterProgram.cpp"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath="..\rendering\style\StyleCustomFilterProgramCache.h"
+                                       >
+                               </File>
+                               <File
+                                       RelativePath="..\rendering\style\StyleCustomFilterProgramCache.cpp"
+                                       >
+                               </File>
+                               <File
                                        RelativePath="..\rendering\style\StyleDeprecatedFlexibleBoxData.cpp"
                                        >
                                        <FileConfiguration
index cc5e73c..9aeb6cf 100644 (file)
                50D40612147D49DE00D30BB5 /* CustomFilterCompiledProgram.h in Headers */ = {isa = PBXBuildFile; fileRef = 50D40610147D49DE00D30BB5 /* CustomFilterCompiledProgram.h */; };
                50D88CB515BDFDAA001809F4 /* CustomFilterProgramInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50D88CB315BDFDAA001809F4 /* CustomFilterProgramInfo.cpp */; };
                50D88CB615BDFDAA001809F4 /* CustomFilterProgramInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 50D88CB415BDFDAA001809F4 /* CustomFilterProgramInfo.h */; };
+               50E18CD816F9285800C65486 /* StyleCustomFilterProgram.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50E18CD516F9285800C65486 /* StyleCustomFilterProgram.cpp */; };
+               50E18CD916F9285800C65486 /* StyleCustomFilterProgramCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 50E18CD616F9285800C65486 /* StyleCustomFilterProgramCache.cpp */; };
+               50E18CDA16F9285800C65486 /* StyleCustomFilterProgramCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 50E18CD716F9285800C65486 /* StyleCustomFilterProgramCache.h */; };
                510184690B08602A004A825F /* CachedPage.h in Headers */ = {isa = PBXBuildFile; fileRef = 510184670B08602A004A825F /* CachedPage.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5101846A0B08602A004A825F /* CachedPage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 510184680B08602A004A825F /* CachedPage.cpp */; };
                510D4A33103165EE0049EA54 /* SocketStreamErrorBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 510D4A2D103165EE0049EA54 /* SocketStreamErrorBase.cpp */; };
                50D40610147D49DE00D30BB5 /* CustomFilterCompiledProgram.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomFilterCompiledProgram.h; path = filters/CustomFilterCompiledProgram.h; sourceTree = "<group>"; };
                50D88CB315BDFDAA001809F4 /* CustomFilterProgramInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CustomFilterProgramInfo.cpp; path = filters/CustomFilterProgramInfo.cpp; sourceTree = "<group>"; };
                50D88CB415BDFDAA001809F4 /* CustomFilterProgramInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomFilterProgramInfo.h; path = filters/CustomFilterProgramInfo.h; sourceTree = "<group>"; };
+               50E18CD516F9285800C65486 /* StyleCustomFilterProgram.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleCustomFilterProgram.cpp; path = style/StyleCustomFilterProgram.cpp; sourceTree = "<group>"; };
+               50E18CD616F9285800C65486 /* StyleCustomFilterProgramCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StyleCustomFilterProgramCache.cpp; path = style/StyleCustomFilterProgramCache.cpp; sourceTree = "<group>"; };
+               50E18CD716F9285800C65486 /* StyleCustomFilterProgramCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StyleCustomFilterProgramCache.h; path = style/StyleCustomFilterProgramCache.h; sourceTree = "<group>"; };
                510184670B08602A004A825F /* CachedPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedPage.h; sourceTree = "<group>"; };
                510184680B08602A004A825F /* CachedPage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedPage.cpp; sourceTree = "<group>"; };
                510D4A2D103165EE0049EA54 /* SocketStreamErrorBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SocketStreamErrorBase.cpp; sourceTree = "<group>"; };
                                9393E603151A9A1800066F06 /* StyleCachedImageSet.h */,
                                5038BE2D1472AD230095E0D1 /* StyleCachedShader.cpp */,
                                5038BE2E1472AD230095E0D1 /* StyleCachedShader.h */,
+                               50E18CD616F9285800C65486 /* StyleCustomFilterProgramCache.cpp */,
+                               50E18CD716F9285800C65486 /* StyleCustomFilterProgramCache.h */,
+                               50E18CD516F9285800C65486 /* StyleCustomFilterProgram.cpp */,
                                503D0CAD14B5B0BA00F32F57 /* StyleCustomFilterProgram.h */,
                                BC5EB67E0E81D4A700B25965 /* StyleDashboardRegion.h */,
                                BC5EB8B60E8201BD00B25965 /* StyleDeprecatedFlexibleBoxData.cpp */,
                                FD537353137B651800008DCE /* ZeroPole.h in Headers */,
                                DAED203116F244480070EC0F /* PageConsole.h in Headers */,
                                2D5BC42716F882EE007048D0 /* SecurityPolicyViolationEvent.h in Headers */,
+                               50E18CDA16F9285800C65486 /* StyleCustomFilterProgramCache.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                FD537352137B651800008DCE /* ZeroPole.cpp in Sources */,
                                DAED203016F2442B0070EC0F /* PageConsole.cpp in Sources */,
                                E1BA003116FB92AC00BA7A35 /* ResourceHandleClient.cpp in Sources */,
+                               50E18CD816F9285800C65486 /* StyleCustomFilterProgram.cpp in Sources */,
+                               50E18CD916F9285800C65486 /* StyleCustomFilterProgramCache.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 4de3762..b88747e 100644 (file)
 #include "CustomFilterNumberParameter.h"
 #include "CustomFilterOperation.h"
 #include "CustomFilterParameter.h"
+#include "CustomFilterProgramInfo.h"
 #include "CustomFilterTransformParameter.h"
 #include "StyleCachedShader.h"
 #include "StyleCustomFilterProgram.h"
+#include "StyleCustomFilterProgramCache.h"
 #include "StylePendingShader.h"
 #include "StyleShader.h"
 #include "WebKitCSSMixFunctionValue.h"
@@ -3941,6 +3943,23 @@ StyleShader* StyleResolver::cachedOrPendingStyleShaderFromValue(WebKitCSSShaderV
     return shader;
 }
 
+PassRefPtr<CustomFilterProgram> StyleResolver::lookupCustomFilterProgram(WebKitCSSShaderValue* vertexShader, WebKitCSSShaderValue* fragmentShader, 
+    CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
+{
+    CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader();
+    KURL vertexShaderURL = vertexShader ? vertexShader->completeURL(cachedResourceLoader) : KURL();
+    KURL fragmentShaderURL = fragmentShader ? fragmentShader->completeURL(cachedResourceLoader) : KURL();
+    RefPtr<StyleCustomFilterProgram> program;
+    if (m_customFilterProgramCache)
+        program = m_customFilterProgramCache->lookup(CustomFilterProgramInfo(vertexShaderURL, fragmentShaderURL, programType, mixSettings, meshType));
+    if (!program) {
+        // Create a new StyleCustomFilterProgram that will be resolved during the loadPendingShaders and added to the cache.
+        program = StyleCustomFilterProgram::create(vertexShaderURL, vertexShader ? styleShader(vertexShader) : 0, 
+            fragmentShaderURL, fragmentShader ? styleShader(fragmentShader) : 0, programType, mixSettings, meshType);
+    }
+    return program.release();
+}
+
 void StyleResolver::loadPendingShaders()
 {
     if (!m_state.style()->hasFilter() || !m_state.hasPendingShaders())
@@ -3955,13 +3974,26 @@ void StyleResolver::loadPendingShaders()
             CustomFilterOperation* customFilter = static_cast<CustomFilterOperation*>(filterOperation.get());
             ASSERT(customFilter->program());
             StyleCustomFilterProgram* program = static_cast<StyleCustomFilterProgram*>(customFilter->program());
-            if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
-                WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
-                program->setVertexShader(shaderValue->cachedShader(cachedResourceLoader));
-            }
-            if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
-                WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
-                program->setFragmentShader(shaderValue->cachedShader(cachedResourceLoader));
+            // Note that the StylePendingShaders could be already resolved to StyleCachedShaders. That's because the rule was matched before.
+            // However, the StyleCustomFilterProgram that was initially created could have been removed from the cache in the meanwhile,
+            // meaning that we get a new StyleCustomFilterProgram here that is not yet in the cache, but already has loaded StyleShaders.
+            if (!program->hasPendingShaders() && program->inCache())
+                continue;
+            if (!m_customFilterProgramCache)
+                m_customFilterProgramCache = adoptPtr(new StyleCustomFilterProgramCache());
+            RefPtr<StyleCustomFilterProgram> styleProgram = m_customFilterProgramCache->lookup(program);
+            if (styleProgram.get())
+                customFilter->setProgram(styleProgram.release());
+            else {
+                if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
+                    WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
+                    program->setVertexShader(shaderValue->cachedShader(cachedResourceLoader));
+                }
+                if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
+                    WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
+                    program->setFragmentShader(shaderValue->cachedShader(cachedResourceLoader));
+                }
+                m_customFilterProgramCache->add(program);
             }
         }
     }
@@ -4105,20 +4137,19 @@ PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWith
     unsigned shadersListLength = shadersList->length();
     ASSERT(shadersListLength);
 
-    RefPtr<StyleShader> vertexShader = styleShader(shadersList->itemWithoutBoundsCheck(0));
-    RefPtr<StyleShader> fragmentShader;
+    WebKitCSSShaderValue* vertexShader = toWebKitCSSShaderValue(shadersList->itemWithoutBoundsCheck(0));
+    WebKitCSSShaderValue* fragmentShader = 0;
     CustomFilterProgramType programType = PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE;
     CustomFilterProgramMixSettings mixSettings;
 
     if (shadersListLength > 1) {
         CSSValue* fragmentShaderOrMixFunction = shadersList->itemWithoutBoundsCheck(1);
-
         if (fragmentShaderOrMixFunction->isWebKitCSSMixFunctionValue()) {
             WebKitCSSMixFunctionValue* mixFunction = static_cast<WebKitCSSMixFunctionValue*>(fragmentShaderOrMixFunction);
             CSSValueListIterator iterator(mixFunction);
 
             ASSERT(mixFunction->length());
-            fragmentShader = styleShader(iterator.value());
+            fragmentShader = toWebKitCSSShaderValue(iterator.value());
             iterator.advance();
 
             ASSERT(mixFunction->length() <= 3);
@@ -4134,9 +4165,12 @@ PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWith
             }
         } else {
             programType = PROGRAM_TYPE_NO_ELEMENT_TEXTURE;
-            fragmentShader = styleShader(fragmentShaderOrMixFunction);
+            fragmentShader = toWebKitCSSShaderValue(fragmentShaderOrMixFunction);
         }
     }
+
+    if (!vertexShader && !fragmentShader)
+        return 0;
     
     unsigned meshRows = 1;
     unsigned meshColumns = 1;
@@ -4192,8 +4226,8 @@ PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWith
     CustomFilterParameterList parameterList;
     if (parametersValue && !parseCustomFilterParameterList(parametersValue, parameterList))
         return 0;
-    
-    RefPtr<StyleCustomFilterProgram> program = StyleCustomFilterProgram::create(vertexShader.release(), fragmentShader.release(), programType, mixSettings, meshType);
+
+    RefPtr<CustomFilterProgram> program = lookupCustomFilterProgram(vertexShader, fragmentShader, programType, mixSettings, meshType);
     return CustomFilterOperation::create(program.release(), parameterList, meshRows, meshColumns, meshType);
 }
 
index 634e6e4..10a4218 100644 (file)
@@ -43,6 +43,9 @@
 #if ENABLE(CSS_FILTERS) && ENABLE(SVG)
 #include "WebKitCSSSVGDocumentValue.h"
 #endif
+#if ENABLE(CSS_SHADERS)
+#include "CustomFilterConstants.h"
+#endif
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 #include <wtf/RefPtr.h>
@@ -72,6 +75,8 @@ class ContainerNode;
 class CustomFilterOperation;
 class CustomFilterParameter;
 class CustomFilterParameterList;
+class CustomFilterProgram;
+struct CustomFilterProgramMixSettings;
 class Document;
 class Element;
 class Frame;
@@ -87,6 +92,7 @@ class RuleData;
 class RuleSet;
 class Settings;
 class StaticCSSRuleList;
+class StyleCustomFilterProgramCache;
 class StyleBuilder;
 class StyleScopeResolver;
 class StyleImage;
@@ -317,6 +323,8 @@ public:
     PassRefPtr<CustomFilterOperation> createCustomFilterOperationWithInlineSyntax(WebKitCSSFilterValue*);
     PassRefPtr<CustomFilterOperation> createCustomFilterOperation(WebKitCSSFilterValue*);
     void loadPendingShaders();
+    PassRefPtr<CustomFilterProgram> lookupCustomFilterProgram(WebKitCSSShaderValue* vertexShader, WebKitCSSShaderValue* fragmentShader, 
+        CustomFilterProgramType, const CustomFilterProgramMixSettings&, CustomFilterMeshType);
 #endif
 #if ENABLE(SVG)
     void loadPendingSVGDocuments();
@@ -631,6 +639,10 @@ private:
 
     State m_state;
 
+#if ENABLE(CSS_SHADERS)
+    OwnPtr<StyleCustomFilterProgramCache> m_customFilterProgramCache;
+#endif
+
     friend class StyleBuilder;
     friend bool operator==(const MatchedProperties&, const MatchedProperties&);
     friend bool operator!=(const MatchedProperties&, const MatchedProperties&);
index fb0b1b1..2df052f 100644 (file)
@@ -37,6 +37,7 @@
 #include "CachedResourceRequest.h"
 #include "CachedResourceRequestInitiators.h"
 #include "Document.h"
+#include "KURL.h"
 #include "StyleCachedShader.h"
 #include "StylePendingShader.h"
 #include "WebCoreMemoryInstrumentation.h"
@@ -54,6 +55,11 @@ WebKitCSSShaderValue::~WebKitCSSShaderValue()
 {
 }
 
+KURL WebKitCSSShaderValue::completeURL(CachedResourceLoader* loader) const
+{
+    return loader->document()->completeURL(m_url);
+}
+
 StyleCachedShader* WebKitCSSShaderValue::cachedShader(CachedResourceLoader* loader)
 {
     ASSERT(loader);
@@ -61,7 +67,7 @@ StyleCachedShader* WebKitCSSShaderValue::cachedShader(CachedResourceLoader* load
     if (!m_accessedShader) {
         m_accessedShader = true;
 
-        CachedResourceRequest request(ResourceRequest(loader->document()->completeURL(m_url)));
+        CachedResourceRequest request(ResourceRequest(completeURL(loader)));
         request.setInitiator(cachedResourceRequestInitiators().css);
         if (CachedResourceHandle<CachedShader> cachedShader = loader->requestShader(request))
             m_shader = StyleCachedShader::create(cachedShader.get());
index 4a9825e..456b5a1 100644 (file)
@@ -37,6 +37,7 @@
 namespace WebCore {
 
 class CachedResourceLoader;
+class KURL;
 class StyleCachedShader;
 class StyleShader;
 
@@ -48,6 +49,7 @@ public:
     const String& format() const { return m_format; }
     void setFormat(const String& format) { m_format = format; }
 
+    KURL completeURL(CachedResourceLoader*) const;
     StyleCachedShader* cachedShader(CachedResourceLoader*);
     StyleShader* cachedOrPendingShader();
 
@@ -66,6 +68,14 @@ private:
     bool m_accessedShader;
 };
 
+// This will catch anyone doing an unnecessary cast.
+WebKitCSSShaderValue* toWebKitCSSShaderValue(const WebKitCSSShaderValue*);
+
+inline WebKitCSSShaderValue* toWebKitCSSShaderValue(CSSValue* value)
+{
+    return value->isWebKitCSSShaderValue() ? static_cast<WebKitCSSShaderValue*>(value) : 0;
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(CSS_SHADERS)
index 9252f47..cde358e 100644 (file)
@@ -63,7 +63,7 @@ PassRefPtr<FilterOperation> CustomFilterOperation::blend(const FilterOperation*
         return this;
     
     const CustomFilterOperation* fromOp = static_cast<const CustomFilterOperation*>(from);
-    if (*m_program.get() != *fromOp->m_program.get()
+    if (m_program.get() != fromOp->m_program.get()
         || m_meshRows != fromOp->m_meshRows
         || m_meshColumns != fromOp->m_meshColumns
         || m_meshType != fromOp->m_meshType)
index 0f92bd9..681c6a7 100644 (file)
@@ -76,7 +76,7 @@ private:
             return false;
 
         const CustomFilterOperation* other = static_cast<const CustomFilterOperation*>(&o);
-        return *m_program.get() == *other->m_program.get()
+        return m_program.get() == other->m_program.get()
             && m_meshRows == other->m_meshRows
             && m_meshColumns == other->m_meshColumns
             && m_meshType == other->m_meshType
index 2a8fce0..e06bb00 100644 (file)
@@ -86,12 +86,5 @@ CustomFilterProgramInfo CustomFilterProgram::programInfo() const
     return CustomFilterProgramInfo(vertexShaderString(), fragmentShaderString(), m_programType, m_mixSettings, m_meshType);
 }
 
-bool CustomFilterProgram::operator==(const CustomFilterProgram& o) const
-{
-    return m_programType == o.m_programType
-        && (m_programType != PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE || m_mixSettings == o.m_mixSettings)
-        && m_meshType == o.m_meshType;
-}
-
 } // namespace WebCore
 #endif // ENABLE(CSS_SHADERS)
index b755bb7..da37e15 100644 (file)
@@ -63,8 +63,6 @@ public:
     CustomFilterProgramMixSettings mixSettings() const { return m_mixSettings; }
     CustomFilterMeshType meshType() const { return m_meshType; }
 
-    virtual bool operator==(const CustomFilterProgram&) const;
-    bool operator!=(const CustomFilterProgram& o) const { return !(*this == o); }
 protected:
     // StyleCustomFilterProgram can notify the clients that the cached resources are
     // loaded and it is ready to create CustomFilterCompiledProgram objects.
@@ -77,6 +75,12 @@ protected:
     CustomFilterProgram(CustomFilterProgramType, const CustomFilterProgramMixSettings&, CustomFilterMeshType);
 
 private:
+    // CustomFilterPrograms are unique combinations of shaders and can be 
+    // compared using just the pointer value instead.
+    // These will catch anyone doing a value equal comparison.
+    bool operator==(const CustomFilterProgram&) const;
+    bool operator!=(const CustomFilterProgram&) const;
+
     typedef HashCountedSet<CustomFilterProgramClient*> CustomFilterProgramClientList;
     CustomFilterProgramClientList m_clients;
     CustomFilterProgramType m_programType;
index 6a49b1b..7f4f154 100644 (file)
@@ -41,17 +41,6 @@ public:
 
     virtual bool isLoaded() const OVERRIDE { return true; }
 
-    virtual bool operator==(const CustomFilterProgram& o) const OVERRIDE
-    {
-        // We don't use the != operator because that would recursively call this method.
-        if (!CustomFilterProgram::operator==(o))
-            return false;
-
-        // The following cast is ugly, but CoordinatedCustomFilterProgram is the single implementation of CustomFilterProgram on UI Process.
-        const CoordinatedCustomFilterProgram* other = static_cast<const CoordinatedCustomFilterProgram*>(&o);
-        return m_vertexShaderString == other->vertexShaderString() && m_fragmentShaderString == other->fragmentShaderString();
-    }
-
 protected:
     virtual String vertexShaderString() const OVERRIDE { return m_vertexShaderString; }
     virtual String fragmentShaderString() const OVERRIDE { return m_fragmentShaderString; }
diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp b/Source/WebCore/rendering/style/StyleCustomFilterProgram.cpp
new file mode 100644 (file)
index 0000000..5f4012f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(CSS_SHADERS)
+
+#include "StyleCustomFilterProgram.h"
+
+#include "StyleCustomFilterProgramCache.h"
+
+namespace WebCore {
+
+StyleCustomFilterProgram::~StyleCustomFilterProgram()
+{
+    if (m_cache)
+        m_cache->remove(this);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SHADERS)
+
index ae68d95..26ac02c 100644 (file)
@@ -35,6 +35,7 @@
 #include "CachedResourceHandle.h"
 #include "CachedShader.h"
 #include "CustomFilterProgram.h"
+#include "KURL.h"
 #include "StyleShader.h"
 #include <wtf/FastAllocBase.h>
 
@@ -42,18 +43,32 @@ namespace WebCore {
 
 // CSS Shaders
 
+class StyleCustomFilterProgramCache;
+
 class StyleCustomFilterProgram : public CustomFilterProgram, public CachedResourceClient {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    static PassRefPtr<StyleCustomFilterProgram> create(PassRefPtr<StyleShader> vertexShader, PassRefPtr<StyleShader> fragmentShader, CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
+    static PassRefPtr<StyleCustomFilterProgram> create(KURL vertexShaderURL, PassRefPtr<StyleShader> vertexShader, 
+        KURL fragmentShaderURL, PassRefPtr<StyleShader> fragmentShader, CustomFilterProgramType programType,
+        const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
     {
-        return adoptRef(new StyleCustomFilterProgram(vertexShader, fragmentShader, programType, mixSettings, meshType));
+        return adoptRef(new StyleCustomFilterProgram(vertexShaderURL, vertexShader, fragmentShaderURL, fragmentShader, programType, mixSettings, meshType));
     }
     
-    void setVertexShader(PassRefPtr<StyleShader> shader) { m_vertexShader = shader; }
+    void setVertexShader(PassRefPtr<StyleShader> shader)
+    {
+        // The shader is immutable while in the cache.
+        ASSERT(!m_cache);
+        m_vertexShader = shader; 
+    }
     StyleShader* vertexShader() const { return m_vertexShader.get(); }
     
-    void setFragmentShader(PassRefPtr<StyleShader> shader) { m_fragmentShader = shader; }
+    void setFragmentShader(PassRefPtr<StyleShader> shader)
+    {
+        // The shader is immutable while in the cache.
+        ASSERT(!m_cache);
+        m_fragmentShader = shader; 
+    }
     StyleShader* fragmentShader() const { return m_fragmentShader.get(); }
     
     virtual String vertexShaderString() const
@@ -72,6 +87,9 @@ public:
     {
         // Do not use the CachedResource:isLoaded method here, because it actually means !isLoading(),
         // so missing and canceled resources will have isLoaded set to true, even if they are not loaded yet.
+        ASSERT(!m_vertexShader || m_vertexShader->isCachedShader());
+        ASSERT(!m_fragmentShader || m_fragmentShader->isCachedShader());
+        ASSERT(m_cachedVertexShader.get() || m_cachedFragmentShader.get());
         return (!m_cachedVertexShader.get() || m_isVertexShaderLoaded)
             && (!m_cachedFragmentShader.get() || m_isFragmentShaderLoaded);
     }
@@ -114,36 +132,49 @@ public:
         if (isLoaded())
             notifyClients();
     }
-    
-    CachedShader* cachedVertexShader() const { return m_vertexShader ? m_vertexShader->cachedShader() : 0; }
-    CachedShader* cachedFragmentShader() const { return m_fragmentShader ? m_fragmentShader->cachedShader() : 0; }
-    
-    virtual bool operator==(const CustomFilterProgram& o) const 
-    {
-        // We don't use the != operator because that would recursively call this method.
-        if (!CustomFilterProgram::operator==(o))
-            return false;
 
-        // The following cast is ugly, but StyleCustomFilterProgram is the single implementation of CustomFilterProgram.
-        const StyleCustomFilterProgram* other = static_cast<const StyleCustomFilterProgram*>(&o);
-        return cachedVertexShader() == other->cachedVertexShader() && cachedFragmentShader() == other->cachedFragmentShader();
+    bool hasPendingShaders() const
+    {
+        return (m_vertexShader && m_vertexShader->isPendingShader()) 
+            || (m_fragmentShader && m_fragmentShader->isPendingShader());
     }
 
+    // StyleCustomFilterProgramCache is responsible with updating the reference to the cache.
+    void setCache(StyleCustomFilterProgramCache* cache) { m_cache = cache; }
+    bool inCache() const { return m_cache; }
+    
+    KURL vertexShaderURL() const { return m_vertexShaderURL; }
+    KURL fragmentShaderURL() const { return m_fragmentShaderURL; }
+
 private:
-    StyleCustomFilterProgram(PassRefPtr<StyleShader> vertexShader, PassRefPtr<StyleShader> fragmentShader, CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
+    StyleCustomFilterProgram(KURL vertexShaderURL, PassRefPtr<StyleShader> vertexShader, KURL fragmentShaderURL, PassRefPtr<StyleShader> fragmentShader, 
+        CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
         : CustomFilterProgram(programType, mixSettings, meshType)
         , m_vertexShader(vertexShader)
         , m_fragmentShader(fragmentShader)
+        , m_vertexShaderURL(vertexShaderURL)
+        , m_fragmentShaderURL(fragmentShaderURL)
+        , m_cache(0)
         , m_isVertexShaderLoaded(false)
         , m_isFragmentShaderLoaded(false)
     {
     }
+
+    ~StyleCustomFilterProgram();
     
     RefPtr<StyleShader> m_vertexShader;
     RefPtr<StyleShader> m_fragmentShader;
-    
+
     CachedResourceHandle<CachedShader> m_cachedVertexShader;
     CachedResourceHandle<CachedShader> m_cachedFragmentShader;
+
+    // The URLs form the key of the StyleCustomFilterProgram in the cache and are used
+    // to lookup the StyleCustomFilterProgram when it's removed from the cache.
+    KURL m_vertexShaderURL;
+    KURL m_fragmentShaderURL;
+
+    // The Cache is responsible of invalidating this reference.
+    StyleCustomFilterProgramCache* m_cache;
     
     bool m_isVertexShaderLoaded;
     bool m_isFragmentShaderLoaded;
diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp b/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.cpp
new file mode 100644 (file)
index 0000000..16b579f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(CSS_SHADERS)
+
+#include "StyleCustomFilterProgramCache.h"
+
+#include "CustomFilterProgramInfo.h"
+#include "StyleCustomFilterProgram.h"
+
+namespace WebCore {
+
+static CustomFilterProgramInfo programCacheKey(StyleCustomFilterProgram* program) 
+{
+    ASSERT(program->vertexShaderURL().isValid() || program->fragmentShaderURL().isValid());
+    return CustomFilterProgramInfo(program->vertexShaderURL(), program->fragmentShaderURL(), 
+        program->programType(), program->mixSettings(), program->meshType());
+}
+
+StyleCustomFilterProgramCache::StyleCustomFilterProgramCache()
+{
+}
+
+StyleCustomFilterProgramCache::~StyleCustomFilterProgramCache()
+{
+    // Make sure the programs are not calling back into this object.
+    for (CacheMap::iterator iter = m_cache.begin(), end = m_cache.end(); iter != end; ++iter)
+        iter->value->setCache(0);
+}
+
+StyleCustomFilterProgram* StyleCustomFilterProgramCache::lookup(const CustomFilterProgramInfo& programInfo) const
+{
+    CacheMap::const_iterator iter = m_cache.find(programInfo);
+    return iter != m_cache.end() ? iter->value : 0;
+}
+
+StyleCustomFilterProgram* StyleCustomFilterProgramCache::lookup(StyleCustomFilterProgram* program) const
+{
+    return lookup(programCacheKey(program));
+}
+
+void StyleCustomFilterProgramCache::add(StyleCustomFilterProgram* program)
+{
+    CustomFilterProgramInfo key = programCacheKey(program);
+    ASSERT(m_cache.find(key) == m_cache.end());
+    m_cache.set(key, program);
+    program->setCache(this);
+}
+
+void StyleCustomFilterProgramCache::remove(StyleCustomFilterProgram* program)
+{
+    CacheMap::iterator iter = m_cache.find(programCacheKey(program));
+    ASSERT(iter != m_cache.end());
+    m_cache.remove(iter);
+}
+
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SHADERS)
+
diff --git a/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h b/Source/WebCore/rendering/style/StyleCustomFilterProgramCache.h
new file mode 100644 (file)
index 0000000..e151836
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef StyleCustomFilterProgramCache_h
+#define StyleCustomFilterProgramCache_h
+
+#if ENABLE(CSS_SHADERS)
+#include "CustomFilterProgramInfo.h"
+#include <wtf/FastAllocBase.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+class StyleCustomFilterProgram;
+class CustomFilterProgramInfo;
+
+class StyleCustomFilterProgramCache {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    StyleCustomFilterProgramCache();
+    ~StyleCustomFilterProgramCache();
+
+    // Lookups a StyleCustomFilterProgram that has similar parameters with the specified program.
+    StyleCustomFilterProgram* lookup(StyleCustomFilterProgram*) const;
+    StyleCustomFilterProgram* lookup(const CustomFilterProgramInfo&) const;
+
+    void add(StyleCustomFilterProgram*);
+    void remove(StyleCustomFilterProgram*);
+
+private:
+    typedef HashMap<CustomFilterProgramInfo, StyleCustomFilterProgram*> CacheMap;
+    CacheMap m_cache;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(CSS_SHADERS)
+
+#endif // StyleCustomFilterProgramCache_h