[BlackBerry] Enable CSS Filter Effects
https://bugs.webkit.org/show_bug.cgi?id=92685

Patch by Joshua Netterfield <jnetterfield@rim.com> on 2012-07-31
Reviewed by Rob Buis.

Enable CSS filter effects, with the exception of custom effects (CSS shaders) and reference effects (SVG effects)

.:

Internally reviewed by Arvid Nilsson <anilsson@rim.com> and Antonio Gomes <agomes@rim.com>.

* Source/cmake/OptionsBlackBerry.cmake: Add LayerFilterRenderer
* Source/cmakeconfig.h.cmake: Acknowledge CSS filter effects

Source/WebCore:

No new tests, because this is covered by tests from other platforms.

Internally reviewed by Arvid Nilsson <anilsson@rim.com> and Antonio Gomes <agomes@rim.com>.

* CMakeLists.txt:
* PlatformBlackBerry.cmake:
* platform/graphics/blackberry/GraphicsLayerBlackBerry.cpp:
(WebCore):
(WebCore::GraphicsLayerBlackBerry::setFilters):
(WebCore::GraphicsLayerBlackBerry::updateFilters):
* platform/graphics/blackberry/GraphicsLayerBlackBerry.h:
(GraphicsLayerBlackBerry):
(WebCore::GraphicsLayerBlackBerry::filters):
* platform/graphics/blackberry/LayerCompositingThread.h:
(LayerOverride):
(WebCore):
(WebCore::LayerCompositingThread::filterOperationsChanged):
(WebCore::LayerCompositingThread::setFilterOperationsChanged):
(LayerCompositingThread):
(WebCore::LayerCompositingThread::filterActions):
(WebCore::LayerCompositingThread::setFilterActions):
* platform/graphics/blackberry/LayerData.h:
(LayerData):
(WebCore::LayerData::filters):
* platform/graphics/blackberry/LayerFilterRenderer.cpp: Added.
(WebCore):
(WebCore::operationTypeToProgramID):
(WebCore::Uniformf::Uniformf):
(WebCore::Uniform1f::apply):
(WebCore::Uniform1f::create):
(WebCore::Uniform1f::Uniform1f):
(WebCore::Uniform2f::apply):
(WebCore::Uniform2f::create):
(WebCore::Uniform2f::Uniform2f):
(WebCore::Uniform3f::apply):
(WebCore::Uniform3f::create):
(WebCore::Uniform3f::Uniform3f):
(WebCore::LayerFilterRendererAction::create):
(WebCore::LayerFilterRendererAction::LayerFilterRendererAction):
(WebCore::LayerFilterRendererAction::~LayerFilterRendererAction):
(WebCore::LayerFilterRendererAction::useActionOn):
(WebCore::LayerFilterRenderer::create):
(WebCore::LayerFilterRenderer::LayerFilterRenderer):
(WebCore::LayerFilterRenderer::bindCommonAttribLocation):
(WebCore::LayerFilterRenderer::initializeSharedGLObjects):
(WebCore::LayerFilterRenderer::ping):
(WebCore::LayerFilterRenderer::pong):
(WebCore::LayerFilterRenderer::pushSnapshot):
(WebCore::LayerFilterRenderer::popSnapshot):
(WebCore::LayerFilterRenderer::actionsForOperations):
(WebCore::LayerFilterRenderer::applyActions):
* platform/graphics/blackberry/LayerFilterRenderer.h: Added.
(WebCore):
(Uniformf):
(WebCore::Uniformf::location):
(Uniform1f):
(Uniform2f):
(Uniform3f):
(LayerFilterRendererAction):
(WebCore::LayerFilterRendererAction::shouldPushSnapshot):
(WebCore::LayerFilterRendererAction::setPushSnapshot):
(WebCore::LayerFilterRendererAction::shouldPopSnapshot):
(WebCore::LayerFilterRendererAction::setPopSnapshot):
(WebCore::LayerFilterRendererAction::appendUniform):
(LayerFilterRenderer):
(WebCore::LayerFilterRenderer::isEnabled):
(WebCore::LayerFilterRenderer::disable):
* platform/graphics/blackberry/LayerRenderer.cpp:
(WebCore::LayerRenderer::loadShader):
(WebCore::LayerRenderer::loadShaderProgram):
(WebCore::LayerRenderer::drawLayersOnSurfaces):
(WebCore::LayerRenderer::updateLayersRecursive):
(WebCore):
(WebCore::LayerRenderer::initializeSharedGLObjects):
* platform/graphics/blackberry/LayerRenderer.h:
(LayerRenderer):
* platform/graphics/blackberry/LayerWebKitThread.cpp:
(WebCore::LayerWebKitThread::LayerWebKitThread):
(WebCore::LayerWebKitThread::commitOnCompositingThread):
(WebCore):
(WebCore::LayerWebKitThread::filtersCanBeComposited):
* platform/graphics/blackberry/LayerWebKitThread.h:
(LayerWebKitThread):
(WebCore::LayerWebKitThread::setFilters):
* platform/graphics/filters/FECustomFilter.cpp:
(WebCore::FECustomFilter::platformApplySoftware):
(WebCore::FECustomFilter::resizeContext):
(WebCore::FECustomFilter::bindProgramAndBuffers):
* platform/graphics/filters/FilterOperation.h:
(WebCore):
(FilterOperation):

Tools:

Internally reviewed by Arvid Nilsson <anilsson@rim.com> and Antonio Gomes <agomes@rim.com>.

* Scripts/webkitperl/FeatureList.pm: Acknowledge CSS filter effects.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@124242 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/ChangeLog b/ChangeLog
index 7b49164..ab81a1d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2012-07-31  Joshua Netterfield  <jnetterfield@rim.com>
+
+        [BlackBerry] Enable CSS Filter Effects
+        https://bugs.webkit.org/show_bug.cgi?id=92685
+
+        Reviewed by Rob Buis.
+
+        Enable CSS filter effects, with the exception of custom effects (CSS shaders) and reference effects (SVG effects)
+
+        Internally reviewed by Arvid Nilsson <anilsson@rim.com> and Antonio Gomes <agomes@rim.com>.
+
+        * Source/cmake/OptionsBlackBerry.cmake: Add LayerFilterRenderer
+        * Source/cmakeconfig.h.cmake: Acknowledge CSS filter effects
+
 2012-07-31  Ryosuke Niwa  <rniwa@webkit.org>
 
         Perf-o-matic: dashboard images are not generated properly from incrementally updated JSON
diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt
index 53610df..23d2521 100644
--- a/Source/WebCore/CMakeLists.txt
+++ b/Source/WebCore/CMakeLists.txt
@@ -1038,6 +1038,7 @@
     css/WebKitCSSMatrix.cpp
     css/WebKitCSSRegionRule.cpp
     css/WebKitCSSSVGDocumentValue.cpp
+    css/WebKitCSSShaderValue.cpp
     css/WebKitCSSTransformValue.cpp
     css/WrapShapeFunctions.cpp
 
@@ -1605,6 +1606,7 @@
     loader/cache/CachedResourceHandle.cpp
     loader/cache/CachedResourceLoader.cpp
     loader/cache/CachedScript.cpp
+    loader/cache/CachedShader.cpp
     loader/cache/CachedSVGDocument.cpp
     loader/cache/CachedTextTrack.cpp
     loader/cache/CachedXSLStyleSheet.cpp
@@ -1821,10 +1823,11 @@
     platform/graphics/TiledBackingStore.cpp
     platform/graphics/WidthIterator.cpp
 
+    platform/graphics/filters/CustomFilterCompiledProgram.cpp
     platform/graphics/filters/CustomFilterGlobalContext.cpp
     platform/graphics/filters/CustomFilterMesh.cpp
+    platform/graphics/filters/CustomFilterOperation.cpp
     platform/graphics/filters/CustomFilterProgram.cpp
-    platform/graphics/filters/CustomFilterCompiledProgram.cpp
     platform/graphics/filters/DistantLightSource.cpp
     platform/graphics/filters/FEBlend.cpp
     platform/graphics/filters/FEColorMatrix.cpp
@@ -1849,16 +1852,15 @@
     platform/graphics/filters/FilterOperations.cpp
     platform/graphics/filters/LightSource.cpp
     platform/graphics/filters/PointLightSource.cpp
-    platform/graphics/filters/SpotLightSource.cpp
     platform/graphics/filters/SourceAlpha.cpp
     platform/graphics/filters/SourceGraphic.cpp
+    platform/graphics/filters/SpotLightSource.cpp
 
     platform/graphics/filters/arm/NEONHelpers.h
     platform/graphics/filters/arm/FEBlendNEON.h
     platform/graphics/filters/arm/FECompositeArithmeticNEON.h
     platform/graphics/filters/arm/FEGaussianBlurNEON.h
     platform/graphics/filters/arm/FELightingNEON.cpp
-    platform/graphics/filters/arm/FELightingNEON.h
 
     platform/graphics/texmap/TextureMapper.cpp
     platform/graphics/texmap/TextureMapperBackingStore.cpp
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 608c8d9..0615639 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,104 @@
+2012-07-31  Joshua Netterfield  <jnetterfield@rim.com>
+
+        [BlackBerry] Enable CSS Filter Effects
+        https://bugs.webkit.org/show_bug.cgi?id=92685
+
+        Reviewed by Rob Buis.
+
+        Enable CSS filter effects, with the exception of custom effects (CSS shaders) and reference effects (SVG effects)
+
+        No new tests, because this is covered by tests from other platforms.
+
+        Internally reviewed by Arvid Nilsson <anilsson@rim.com> and Antonio Gomes <agomes@rim.com>.
+
+        * CMakeLists.txt:
+        * PlatformBlackBerry.cmake:
+        * platform/graphics/blackberry/GraphicsLayerBlackBerry.cpp:
+        (WebCore):
+        (WebCore::GraphicsLayerBlackBerry::setFilters):
+        (WebCore::GraphicsLayerBlackBerry::updateFilters):
+        * platform/graphics/blackberry/GraphicsLayerBlackBerry.h:
+        (GraphicsLayerBlackBerry):
+        (WebCore::GraphicsLayerBlackBerry::filters):
+        * platform/graphics/blackberry/LayerCompositingThread.h:
+        (LayerOverride):
+        (WebCore):
+        (WebCore::LayerCompositingThread::filterOperationsChanged):
+        (WebCore::LayerCompositingThread::setFilterOperationsChanged):
+        (LayerCompositingThread):
+        (WebCore::LayerCompositingThread::filterActions):
+        (WebCore::LayerCompositingThread::setFilterActions):
+        * platform/graphics/blackberry/LayerData.h:
+        (LayerData):
+        (WebCore::LayerData::filters):
+        * platform/graphics/blackberry/LayerFilterRenderer.cpp: Added.
+        (WebCore):
+        (WebCore::operationTypeToProgramID):
+        (WebCore::Uniformf::Uniformf):
+        (WebCore::Uniform1f::apply):
+        (WebCore::Uniform1f::create):
+        (WebCore::Uniform1f::Uniform1f):
+        (WebCore::Uniform2f::apply):
+        (WebCore::Uniform2f::create):
+        (WebCore::Uniform2f::Uniform2f):
+        (WebCore::Uniform3f::apply):
+        (WebCore::Uniform3f::create):
+        (WebCore::Uniform3f::Uniform3f):
+        (WebCore::LayerFilterRendererAction::create):
+        (WebCore::LayerFilterRendererAction::LayerFilterRendererAction):
+        (WebCore::LayerFilterRendererAction::~LayerFilterRendererAction):
+        (WebCore::LayerFilterRendererAction::useActionOn):
+        (WebCore::LayerFilterRenderer::create):
+        (WebCore::LayerFilterRenderer::LayerFilterRenderer):
+        (WebCore::LayerFilterRenderer::bindCommonAttribLocation):
+        (WebCore::LayerFilterRenderer::initializeSharedGLObjects):
+        (WebCore::LayerFilterRenderer::ping):
+        (WebCore::LayerFilterRenderer::pong):
+        (WebCore::LayerFilterRenderer::pushSnapshot):
+        (WebCore::LayerFilterRenderer::popSnapshot):
+        (WebCore::LayerFilterRenderer::actionsForOperations):
+        (WebCore::LayerFilterRenderer::applyActions):
+        * platform/graphics/blackberry/LayerFilterRenderer.h: Added.
+        (WebCore):
+        (Uniformf):
+        (WebCore::Uniformf::location):
+        (Uniform1f):
+        (Uniform2f):
+        (Uniform3f):
+        (LayerFilterRendererAction):
+        (WebCore::LayerFilterRendererAction::shouldPushSnapshot):
+        (WebCore::LayerFilterRendererAction::setPushSnapshot):
+        (WebCore::LayerFilterRendererAction::shouldPopSnapshot):
+        (WebCore::LayerFilterRendererAction::setPopSnapshot):
+        (WebCore::LayerFilterRendererAction::appendUniform):
+        (LayerFilterRenderer):
+        (WebCore::LayerFilterRenderer::isEnabled):
+        (WebCore::LayerFilterRenderer::disable):
+        * platform/graphics/blackberry/LayerRenderer.cpp:
+        (WebCore::LayerRenderer::loadShader):
+        (WebCore::LayerRenderer::loadShaderProgram):
+        (WebCore::LayerRenderer::drawLayersOnSurfaces):
+        (WebCore::LayerRenderer::updateLayersRecursive):
+        (WebCore):
+        (WebCore::LayerRenderer::initializeSharedGLObjects):
+        * platform/graphics/blackberry/LayerRenderer.h:
+        (LayerRenderer):
+        * platform/graphics/blackberry/LayerWebKitThread.cpp:
+        (WebCore::LayerWebKitThread::LayerWebKitThread):
+        (WebCore::LayerWebKitThread::commitOnCompositingThread):
+        (WebCore):
+        (WebCore::LayerWebKitThread::filtersCanBeComposited):
+        * platform/graphics/blackberry/LayerWebKitThread.h:
+        (LayerWebKitThread):
+        (WebCore::LayerWebKitThread::setFilters):
+        * platform/graphics/filters/FECustomFilter.cpp:
+        (WebCore::FECustomFilter::platformApplySoftware):
+        (WebCore::FECustomFilter::resizeContext):
+        (WebCore::FECustomFilter::bindProgramAndBuffers):
+        * platform/graphics/filters/FilterOperation.h:
+        (WebCore):
+        (FilterOperation):
+
 2012-07-31  Alexis Menard  <alexis.menard@openbossa.org>
 
         Get rid of "parser" type casts in CSSGrammar.y
diff --git a/Source/WebCore/PlatformBlackBerry.cmake b/Source/WebCore/PlatformBlackBerry.cmake
index 1ae5fe6..a816b14 100644
--- a/Source/WebCore/PlatformBlackBerry.cmake
+++ b/Source/WebCore/PlatformBlackBerry.cmake
@@ -272,6 +272,7 @@
         ${WEBCORE_DIR}/platform/graphics/blackberry/GraphicsLayerBlackBerry.cpp
         ${WEBCORE_DIR}/platform/graphics/blackberry/LayerAnimation.cpp
         ${WEBCORE_DIR}/platform/graphics/blackberry/LayerCompositingThread.cpp
+        ${WEBCORE_DIR}/platform/graphics/blackberry/LayerFilterRenderer.cpp
         ${WEBCORE_DIR}/platform/graphics/blackberry/LayerRenderer.cpp
         ${WEBCORE_DIR}/platform/graphics/blackberry/LayerRendererSurface.cpp
         ${WEBCORE_DIR}/platform/graphics/blackberry/LayerTile.cpp
diff --git a/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.cpp b/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.cpp
index 1b81f54..e2779c3 100644
--- a/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.cpp
+++ b/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.cpp
@@ -51,6 +51,7 @@
 #include "Image.h"
 #include "LayerAnimation.h"
 #include "LayerWebKitThread.h"
+#include "NotImplemented.h"
 
 namespace WebCore {
 
@@ -292,6 +293,26 @@
     updateHasFixedAncestorInDOMTree();
 }
 
+#if ENABLE(CSS_FILTERS)
+bool GraphicsLayerBlackBerry::setFilters(const FilterOperations& filters)
+{
+    if (m_filters == filters)
+        return true;
+
+    bool canCompositeFilters = LayerWebKitThread::filtersCanBeComposited(filters);
+    if (canCompositeFilters) {
+        m_filters = filters;
+        GraphicsLayer::setFilters(filters);
+        updateFilters();
+    } else {
+        m_filters.clear();
+        notImplemented();
+    }
+
+    return canCompositeFilters;
+}
+#endif
+
 void GraphicsLayerBlackBerry::setBackgroundColor(const Color& color)
 {
     if (m_backgroundColorSet && m_backgroundColor == color)
@@ -803,6 +824,16 @@
         clearLayerBackgroundColor(*m_contentsLayer);
 }
 
+#if ENABLE(CSS_FILTERS)
+void GraphicsLayerBlackBerry::updateFilters()
+{
+    if (!m_filters.size())
+        return;
+
+    primaryLayer()->setFilters(m_filters);
+}
+#endif
+
 void GraphicsLayerBlackBerry::updateAnimations()
 {
     // When there is a transform layer, the transform must be set on that layer
diff --git a/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.h b/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.h
index c266947..d8d6b6a 100644
--- a/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.h
+++ b/Source/WebCore/platform/graphics/blackberry/GraphicsLayerBlackBerry.h
@@ -29,13 +29,15 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "Platform.h"
+
 #ifndef GraphicsLayerBlackBerry_h
 #define GraphicsLayerBlackBerry_h
 
 #if USE(ACCELERATED_COMPOSITING)
 
+#include "FilterOperations.h"
 #include "GraphicsLayer.h"
-
 #include <wtf/Vector.h>
 
 namespace WebCore {
@@ -77,6 +79,12 @@
     virtual void setHasFixedContainer(bool);
     virtual void setHasFixedAncestorInDOMTree(bool);
 
+#if ENABLE(CSS_FILTERS)
+    // Returns true if filter can be rendered by the compositor
+    virtual bool setFilters(const FilterOperations &);
+    const FilterOperations& filters() const { return m_filters; }
+#endif
+
     virtual void setBackgroundColor(const Color&);
     virtual void clearBackgroundColor();
 
@@ -146,6 +154,9 @@
     void updateHasFixedContainer();
     void updateHasFixedAncestorInDOMTree();
     void updateLayerBackgroundColor();
+#if ENABLE(CSS_FILTERS)
+    void updateFilters();
+#endif
     void updateAnimations();
 
     void updateContentsImage(Image*);
@@ -159,6 +170,10 @@
     RefPtr<LayerWebKitThread> m_transformLayer;
     RefPtr<LayerWebKitThread> m_contentsLayer;
 
+#if ENABLE(CSS_FILTERS)
+    FilterOperations m_filters;
+#endif
+
     Vector<RefPtr<LayerAnimation> > m_runningAnimations;
     Vector<RefPtr<LayerAnimation> > m_suspendedAnimations;
     double m_suspendTime;
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.cpp b/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.cpp
index c750ebd..81c9180 100644
--- a/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.cpp
+++ b/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.cpp
@@ -79,6 +79,9 @@
     , m_visible(false)
     , m_commitScheduled(false)
     , m_client(client)
+#if ENABLE(CSS_FILTERS)
+    , m_filterOperationsChanged(false)
+#endif
 {
 }
 
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.h b/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.h
index b335606..df07844 100644
--- a/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.h
+++ b/Source/WebCore/platform/graphics/blackberry/LayerCompositingThread.h
@@ -35,9 +35,11 @@
 
 #if USE(ACCELERATED_COMPOSITING)
 
+#include "FilterOperations.h"
 #include "FloatQuad.h"
 #include "LayerAnimation.h"
 #include "LayerData.h"
+#include "LayerFilterRenderer.h"
 #include "LayerRendererSurface.h"
 #include "LayerTiler.h"
 
@@ -101,6 +103,7 @@
     IntSize m_bounds;
     TransformationMatrix m_transform;
     float m_opacity;
+
     Vector<RefPtr<LayerAnimation> > m_animations;
 
     unsigned m_positionSet : 1;
@@ -110,6 +113,8 @@
     unsigned m_opacitySet : 1;
 };
 
+class LayerFilterRendererAction;
+
 class LayerCompositingThread : public ThreadSafeRefCounted<LayerCompositingThread>, public LayerData, public BlackBerry::Platform::GuardedPointerBase {
 public:
     static PassRefPtr<LayerCompositingThread> create(LayerType, LayerCompositingThreadClient*);
@@ -207,6 +212,14 @@
     LayerOverride* override();
     void clearOverride();
 
+#if ENABLE(CSS_FILTERS)
+    bool filterOperationsChanged() const { return m_filterOperationsChanged; }
+    void setFilterOperationsChanged(bool changed) { m_filterOperationsChanged = changed; }
+
+    Vector<RefPtr<LayerFilterRendererAction> > filterActions() const { return m_filterActions; }
+    void setFilterActions(const Vector<RefPtr<LayerFilterRendererAction> >& actions) { m_filterActions = actions; }
+#endif
+
 protected:
     virtual ~LayerCompositingThread();
 
@@ -251,6 +264,11 @@
 
     OwnPtr<LayerOverride> m_override;
     LayerCompositingThreadClient* m_client;
+
+#if ENABLE(CSS_FILTERS)
+    bool m_filterOperationsChanged;
+    Vector<RefPtr<LayerFilterRendererAction> > m_filterActions;
+#endif
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerData.h b/Source/WebCore/platform/graphics/blackberry/LayerData.h
index d991215..7ec581b 100644
--- a/Source/WebCore/platform/graphics/blackberry/LayerData.h
+++ b/Source/WebCore/platform/graphics/blackberry/LayerData.h
@@ -34,6 +34,7 @@
 #define LayerData_h
 
 #include "Color.h"
+#include "FilterOperations.h"
 #include "FloatPoint.h"
 #include "FloatRect.h"
 #include "IntRect.h"
@@ -59,6 +60,25 @@
                               LayerProgramShaderBGRA,
                               NumberOfLayerProgramShaders };
 
+#if ENABLE(CSS_FILTERS)
+    enum CSSFilterShaders { CSSFilterShaderGrayscale = 0,
+                            CSSFilterShaderSepia,
+                            CSSFilterShaderSaturate,
+                            CSSFilterShaderHueRotate,
+                            CSSFilterShaderInvert,
+                            CSSFilterShaderBrightness,
+                            CSSFilterShaderContrast,
+                            CSSFilterShaderOpacity,
+                            CSSFilterShaderBlurY,
+                            CSSFilterShaderBlurX,
+                            CSSFilterShaderShadow,
+                            CSSFilterShaderPassthrough,
+#if ENABLE(CSS_SHADERS)
+                            CSSFilterShaderCustom,
+#endif
+                            NumberOfCSSFilterShaders };
+#endif
+
     LayerData(LayerType type)
         : m_layerType(type)
         , m_anchorPoint(0.5, 0.5)
@@ -115,6 +135,10 @@
 
     float opacity() const { return m_opacity; }
 
+#if ENABLE(CSS_FILTERS)
+    FilterOperations filters() const { return m_filters; }
+#endif
+
     bool isOpaque() const { return m_isOpaque; }
 
     FloatPoint position() const { return m_position; }
@@ -177,6 +201,9 @@
     TransformationMatrix m_sublayerTransform;
 
     float m_opacity;
+#if ENABLE(CSS_FILTERS)
+    FilterOperations m_filters;
+#endif
     float m_anchorPointZ;
     float m_borderWidth;
 
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerFilterRenderer.cpp b/Source/WebCore/platform/graphics/blackberry/LayerFilterRenderer.cpp
new file mode 100644
index 0000000..8797c10
--- /dev/null
+++ b/Source/WebCore/platform/graphics/blackberry/LayerFilterRenderer.cpp
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING) && ENABLE(CSS_FILTERS)
+
+#include "LayerFilterRenderer.h"
+
+#include "FilterOperation.h"
+#include "LayerCompositingThread.h"
+#include "LayerRenderer.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include "TextureCacheCompositingThread.h"
+
+#include <BlackBerryPlatformGraphics.h>
+#include <BlackBerryPlatformLog.h>
+#include <Vector.h>
+
+#include <cstring>
+#include <limits>
+
+namespace WebCore {
+
+static int operationTypeToProgramID(const FilterOperation::OperationType& t)
+{
+    switch (t) {
+    case FilterOperation::GRAYSCALE:
+        return LayerData::CSSFilterShaderGrayscale;
+    case FilterOperation::SEPIA:
+        return LayerData::CSSFilterShaderSepia;
+    case FilterOperation::SATURATE:
+        return LayerData::CSSFilterShaderSaturate;
+    case FilterOperation::HUE_ROTATE:
+        return LayerData::CSSFilterShaderHueRotate;
+    case FilterOperation::INVERT:
+        return LayerData::CSSFilterShaderInvert;
+    case FilterOperation::OPACITY:
+        return LayerData::CSSFilterShaderOpacity;
+    case FilterOperation::BRIGHTNESS:
+        return LayerData::CSSFilterShaderBrightness;
+    case FilterOperation::CONTRAST:
+        return LayerData::CSSFilterShaderContrast;
+    case FilterOperation::BLUR:
+        return LayerData::CSSFilterShaderBlurY;
+    case FilterOperation::DROP_SHADOW:
+        return LayerData::CSSFilterShaderShadow;
+#if ENABLE(CSS_SHADERS)
+    case FilterOperation::CUSTOM:
+        return LayerData::CSSFilterCustom;
+#endif
+    default:
+        ASSERT_NOT_REACHED();
+        return -1;
+    }
+}
+
+Uniformf::Uniformf(int c_location)
+    : m_location(c_location)
+{
+}
+
+void Uniform1f::apply()
+{
+    glUniform1f(location(), m_val);
+}
+
+PassRefPtr<Uniformf> Uniform1f::create(int location, float val)
+{
+    return adoptRef(new Uniform1f(location, val));
+}
+
+Uniform1f::Uniform1f(int c_location, float c_val)
+    : Uniformf(c_location)
+    , m_val(c_val)
+{
+}
+
+void Uniform2f::apply()
+{
+    glUniform2f(location(), m_val[0], m_val[1]);
+}
+
+PassRefPtr<Uniformf> Uniform2f::create(int location, float val0, float val1)
+{
+    return adoptRef(new Uniform2f(location, val0, val1));
+}
+
+Uniform2f::Uniform2f(int c_location, float c_val0, float c_val1)
+    : Uniformf(c_location)
+{
+    m_val[0] = c_val0;
+    m_val[1] = c_val1;
+}
+
+void Uniform3f::apply()
+{
+    glUniform3f(location(), m_val[0], m_val[1], m_val[2]);
+}
+
+PassRefPtr<Uniformf> Uniform3f::create(int location, float val0, float val1, float val2)
+{
+    return adoptRef(new Uniform3f(location, val0, val1, val2));
+}
+
+Uniform3f::Uniform3f(int c_location, float c_val0, float c_val1, float c_val2)
+    : Uniformf(c_location)
+{
+    m_val[0] = c_val0;
+    m_val[1] = c_val1;
+    m_val[2] = c_val2;
+}
+
+PassRefPtr<LayerFilterRendererAction> LayerFilterRendererAction::create(int programId)
+{
+    return adoptRef(new LayerFilterRendererAction(programId));
+}
+
+LayerFilterRendererAction::LayerFilterRendererAction(int c_programId)
+    , m_programId(c_programId)
+    , m_pushSnapshot(false)
+    , m_popSnapshot(false)
+{
+}
+
+void LayerFilterRendererAction::useActionOn(LayerFilterRenderer* renderer)
+{
+    ASSERT(m_programId != -1);
+    if (m_programId == -1) {
+        glUseProgram(renderer->m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]);
+        return;
+    }
+    glUseProgram(renderer->m_cssFilterProgramObject[m_programId]);
+    for (unsigned i = 0; i < m_uniforms.size(); ++i)
+        m_uniforms[i]->apply();
+}
+
+PassOwnPtr<LayerFilterRenderer> LayerFilterRenderer::create(const int& positionLocation, const int& texCoordLocation)
+{
+    return adoptPtr(new LayerFilterRenderer(positionLocation, texCoordLocation));
+}
+
+LayerFilterRenderer::LayerFilterRenderer(const int& positionLocation, const int& texCoordLocation)
+    : m_positionLocation(positionLocation)
+    , m_texCoordLocation(texCoordLocation)
+{
+    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
+        m_cssFilterProgramObject[i] = 0;
+
+    if (!(m_enabled = initializeSharedGLObjects()))
+        BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "CSS Filters are not enabled due to failed initialization.");
+}
+
+// Binds the given attribute name to a common location across all programs
+// used by the compositor. This allows the code to bind the attributes only once
+// even when switching between programs.
+//
+// This is an extension of LayerRenderer::bindCommonAttribLocation and the locations
+// will match those of LayerRenderer. See LayerFilterRenderer::LayerFilterRenderer()
+void LayerFilterRenderer::bindCommonAttribLocation(int location, const char* attribName)
+{
+    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
+        glBindAttribLocation(m_cssFilterProgramObject[i], location, attribName);
+}
+
+bool LayerFilterRenderer::initializeSharedGLObjects()
+{
+    // See also TextureMapperShaderManager.cpp
+
+    char vertexShaderString[] =
+        "attribute vec4 a_position;   \n"
+        "attribute vec2 a_texCoord;   \n"
+        "varying vec2 v_texCoord;     \n"
+        "void main()                  \n"
+        "{                            \n"
+        "  gl_Position = a_position;  \n"
+        "  v_texCoord = a_texCoord;   \n"
+        "}                            \n";
+
+#define STANDARD_FILTER(x...) \
+        "precision mediump float; \n"\
+        "\n"\
+        "varying mediump vec2 v_texCoord;\n"\
+        "uniform lowp sampler2D s_texture;\n"\
+        "uniform highp float u_amount;\n"\
+        #x\
+        "void main(void)\n { gl_FragColor = shade(texture2D(s_texture, v_texCoord)); }"
+
+#define OFFSET_FILTER(x...) \
+        "precision mediump float; \n"\
+        "\n"\
+        "varying mediump vec2 v_texCoord;\n"\
+        "uniform lowp sampler2D s_texture;\n"\
+        "uniform highp float u_amount;\n"\
+        "uniform mediump vec2 u_offset;\n"\
+        #x\
+        "void main(void)\n { gl_FragColor = shade(texture2D(s_texture, v_texCoord - u_offset)); }"
+
+#define BLUR_FILTER(x...) \
+        "precision highp float; \n"\
+        "\n"\
+        "varying mediump vec2 v_texCoord;\n"\
+        "uniform lowp sampler2D s_texture;\n"\
+        "uniform highp float u_amount;\n"\
+        "uniform highp float u_blurSize;\n"\
+        "const float pi = 3.1415927;\n"\
+        #x\
+        "void main(void)\n"\
+        "{\n"\
+        "vec3 incr;\n"\
+        "incr.x = 1.0 / (sqrt(2.0 * pi) * u_amount);\n"\
+        "incr.y = exp(-0.5 / (u_amount * u_amount));\n"\
+        "incr.z = incr.y * incr.y;\n"\
+        "\n"\
+        "vec4 avg = vec4(0.0, 0.0, 0.0, 0.0);\n"\
+        "float coefficientSum = 0.0;\n"\
+        "\n"\
+        "avg += texture2D(s_texture, v_texCoord.xy) * incr.x;\n"\
+        "coefficientSum += incr.x;\n"\
+        "incr.xy *= incr.yz;\n"\
+        "\n"\
+        "for (float i = 1.0; i <= numBlurPixelsPerSide; i++) {\n"\
+        "    avg += texture2D(s_texture, v_texCoord.xy - i * u_blurSize * blurMultiplyVec) * incr.x;\n"\
+        "    avg += texture2D(s_texture, v_texCoord.xy + i * u_blurSize * blurMultiplyVec) * incr.x;\n"\
+        "    coefficientSum += 2.0 * incr.x;\n"\
+        "    incr.xy *= incr.yz;\n"\
+        "}\n"\
+        "\n"\
+        "gl_FragColor = avg / coefficientSum;\n"\
+        "}"
+
+    const char* shaderStrs[LayerData::NumberOfCSSFilterShaders];
+
+    shaderStrs[LayerData::CSSFilterShaderGrayscale] = STANDARD_FILTER(
+        lowp vec4 shade(lowp vec4 color)
+        {
+            lowp float amount = 1.0 - u_amount;
+            return vec4((0.2126 + 0.7874 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
+                        (0.2126 - 0.2126 * amount) * color.r + (0.7152 + 0.2848 * amount) * color.g + (0.0722 - 0.0722 * amount) * color.b,
+                        (0.2126 - 0.2126 * amount) * color.r + (0.7152 - 0.7152 * amount) * color.g + (0.0722 + 0.9278 * amount) * color.b,
+                        color.a);
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderSepia] = STANDARD_FILTER(
+        lowp vec4 shade(lowp vec4 color)
+        {
+            lowp float amount = 1.0 - u_amount;
+            return vec4((0.393 + 0.607 * amount) * color.r + (0.769 - 0.769 * amount) * color.g + (0.189 - 0.189 * amount) * color.b,
+                        (0.349 - 0.349 * amount) * color.r + (0.686 + 0.314 * amount) * color.g + (0.168 - 0.168 * amount) * color.b,
+                        (0.272 - 0.272 * amount) * color.r + (0.534 - 0.534 * amount) * color.g + (0.131 + 0.869 * amount) * color.b,
+                        color.a);
+         }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderSaturate] = STANDARD_FILTER(
+        lowp vec4 shade(lowp vec4 color)
+        {
+            return vec4((0.213 + 0.787 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b,
+                        (0.213 - 0.213 * u_amount) * color.r + (0.715 + 0.285 * u_amount) * color.g + (0.072 - 0.072 * u_amount) * color.b,
+                        (0.213 - 0.213 * u_amount) * color.r + (0.715 - 0.715 * u_amount) * color.g + (0.072 + 0.928 * u_amount) * color.b,
+                        color.a);
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderHueRotate] = STANDARD_FILTER(
+        lowp vec4 shade(lowp vec4 color)
+        {
+            highp float pi = 3.14159265358979323846;
+            highp float c = cos(u_amount * pi / 180.0);
+            highp float s = sin(u_amount * pi / 180.0);
+            return vec4(color.r * (0.213 + c * 0.787 - s * 0.213) + color.g * (0.715 - c * 0.715 - s * 0.715) + color.b * (0.072 - c * 0.072 + s * 0.928),
+                        color.r * (0.213 - c * 0.213 + s * 0.143) + color.g * (0.715 + c * 0.285 + s * 0.140) + color.b * (0.072 - c * 0.072 - s * 0.283),
+                        color.r * (0.213 - c * 0.213 - s * 0.787) +  color.g * (0.715 - c * 0.715 + s * 0.715) + color.b * (0.072 + c * 0.928 + s * 0.072),
+                        color.a);
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderInvert] = STANDARD_FILTER(
+        lowp float invert(lowp float n) { return (1.0 - n) * u_amount + n * (1.0 - u_amount); }
+        lowp vec4 shade(lowp vec4 color)
+        {
+            return vec4(invert(color.r), invert(color.g), invert(color.b), color.a);
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderBrightness] = STANDARD_FILTER(
+        lowp vec4 shade(lowp vec4 color)
+        {
+            return vec4(color.rgb * (1.0 + u_amount), color.a);
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderContrast] = STANDARD_FILTER(
+        lowp float contrast(lowp float n) { return (n - 0.5) * u_amount + 0.5; }
+        lowp vec4 shade(lowp vec4 color)
+        {
+            return vec4(contrast(color.r), contrast(color.g), contrast(color.b), color.a);
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderOpacity] = STANDARD_FILTER(
+        lowp vec4 shade(lowp vec4 color)
+        {
+            return vec4(color.r, color.g, color.b, color.a * u_amount);
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderBlurX] = BLUR_FILTER(
+        const float numBlurPixelsPerSide = 2.0;
+        const vec2  blurMultiplyVec      = vec2(1.0, 0.0);
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderBlurY] = BLUR_FILTER(
+        const float numBlurPixelsPerSide = 2.0;
+        const vec2  blurMultiplyVec      = vec2(0.0, 1.0);
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderShadow] = OFFSET_FILTER(
+        uniform lowp vec3 u_color;
+        lowp vec4 shade(lowp vec4 color)
+        {
+            if (color.a > 0.5)
+                return vec4(u_color.r, u_color.g, u_color.b, color.a);
+            return color;
+        }
+    );
+
+    shaderStrs[LayerData::CSSFilterShaderPassthrough] = STANDARD_FILTER(
+        lowp vec4 shade(lowp vec4 color)
+        {
+            return color;
+        }
+    );
+
+    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; i++) {
+        m_cssFilterProgramObject[i] = LayerRenderer::loadShaderProgram(vertexShaderString, shaderStrs[i]);
+        if (!m_cssFilterProgramObject[i]) {
+            BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelWarn, "Could not load CSS Filter Shader %i", i);
+            return false;
+        }
+    }
+
+    // Set ATTRIB locations - these will be the same as the programs in LayerRenderer.cpp
+    bindCommonAttribLocation(m_positionLocation, "a_position");
+    bindCommonAttribLocation(m_texCoordLocation, "a_texCoord");
+
+    // Re-link to take effect
+    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
+        glLinkProgram(m_cssFilterProgramObject[i]);
+
+    // Get UNIFORM locations
+    for (int i = 0; i < LayerData::NumberOfCSSFilterShaders; ++i)
+        m_amountLocation[i] = glGetUniformLocation(m_cssFilterProgramObject[i], "u_amount");
+
+    m_blurAmountLocation[0] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurY], "u_blurSize");
+    m_blurAmountLocation[1] = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderBlurX], "u_blurSize");
+
+    m_shadowColorLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_color");
+    m_offsetLocation = glGetUniformLocation(m_cssFilterProgramObject[LayerData::CSSFilterShaderShadow], "u_offset");
+
+    return true;
+}
+
+void LayerFilterRenderer::ping(LayerRendererSurface* surface)
+{
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture->textureId(), 0);
+    glBindTexture(GL_TEXTURE_2D, surface->texture()->textureId());
+}
+
+void LayerFilterRenderer::pong(LayerRendererSurface* surface)
+{
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->texture()->textureId(), 0);
+    glBindTexture(GL_TEXTURE_2D, m_texture->textureId());
+}
+
+void LayerFilterRenderer::pushSnapshot(LayerRendererSurface* surface, int sourceId)
+{
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_snapshotTexture->textureId(), 0);
+
+    glBindTexture(GL_TEXTURE_2D, sourceId);
+    glClear(GL_COLOR_BUFFER_BIT); // to transparency
+
+    glViewport(0, 0, surface->size().width(), surface->size().height());
+
+    glUseProgram(m_cssFilterProgramObject[LayerData::CSSFilterShaderPassthrough]);
+    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
+
+void LayerFilterRenderer::popSnapshot()
+{
+    // The name is slightly misleading.
+    // This DRAWS the previous texture using the current LayerFilterRendererAction, then sets the texture
+    // to the snapshot texture. Next time glDrawArrays is called, the snapshot will be drawn.
+
+    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+    glBindTexture(GL_TEXTURE_2D, m_snapshotTexture->textureId());
+}
+
+Vector<RefPtr<LayerFilterRendererAction> > LayerFilterRenderer::actionsForOperations(LayerRendererSurface* surface, const Vector<RefPtr<FilterOperation> >& ops)
+{
+    Vector<RefPtr<LayerFilterRendererAction> > ret;
+    for (unsigned int i = 0; i < ops.size(); ++i) {
+        const FilterOperation& operation = *ops[i].get();
+        if (operation.getOperationType() == FilterOperation::BLUR && static_cast<const BlurFilterOperation&>(operation).stdDeviation().value() < 0.1)
+            continue;
+
+        int programId = operationTypeToProgramID(operation.getOperationType());
+        ret.append(LayerFilterRendererAction::create(programId));
+
+        switch (operation.getOperationType()) {
+        case FilterOperation::GRAYSCALE:
+        case FilterOperation::SEPIA:
+        case FilterOperation::SATURATE:
+        case FilterOperation::HUE_ROTATE:
+            ret.last()->appendUniform(Uniform1f::create(m_amountLocation[programId]
+                , static_cast<const BasicColorMatrixFilterOperation&>(operation).amount()));
+            break;
+        case FilterOperation::INVERT:
+        case FilterOperation::BRIGHTNESS:
+        case FilterOperation::CONTRAST:
+        case FilterOperation::OPACITY:
+            ret.last()->appendUniform(Uniform1f::create(m_amountLocation[programId]
+                , static_cast<const BasicComponentTransferFilterOperation&>(operation).amount()));
+            break;
+        case FilterOperation::BLUR:
+            {
+            // Blur is a two-step process:
+            //     1. blur X
+            //     2. blur Y
+            // This way we can have 2n time instead of n^2 time)
+
+            double amount = static_cast<const BlurFilterOperation&>(operation).stdDeviation().value();
+
+            // BLUR Y:
+            ret.last()->appendUniform(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY], amount));
+            ret.last()->appendUniform(Uniform1f::create(m_blurAmountLocation[0]
+                , 1.0f / float(surface->size().height())));
+
+            // BLUR X:
+            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX));
+            ret.last()->appendUniform(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX], amount));
+            ret.last()->appendUniform(Uniform1f::create(m_blurAmountLocation[1]
+                , 1.0f / float(surface->size().width())));
+
+            }
+            break;
+        case FilterOperation::DROP_SHADOW:
+            {
+            // Shadow is a four-step process:
+            //     1. capture snapshot
+            //        turn into a solid offset mask
+            //     2. blur X
+            //     3. blur Y
+            //     4. repaint original on top of mask
+            const DropShadowFilterOperation& dsfo = static_cast<const DropShadowFilterOperation&>(operation);
+            ret.last()->setPushSnapshot();
+            ret.last()->appendUniform(Uniform2f::create(m_offsetLocation
+                , float(dsfo.x()) / float(surface->size().width())
+                , float(dsfo.y()) / float(surface->size().height())));
+            ret.last()->appendUniform(Uniform3f::create(m_shadowColorLocation
+                , float(dsfo.color().red()) / 255.0f
+                , float(dsfo.color().green()) / 255.0f
+                , float(dsfo.color().blue()) / 255.0f));
+
+            // BLUR Y
+            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurY));
+            ret.last()->appendUniform(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurY]
+                , dsfo.stdDeviation()));
+            ret.last()->appendUniform(Uniform1f::create(m_blurAmountLocation[0]
+                , 1.0f / float(surface->size().height())));
+
+            // BLUR X
+            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderBlurX));
+            ret.last()->appendUniform(Uniform1f::create(m_amountLocation[LayerData::CSSFilterShaderBlurX]
+                , dsfo.stdDeviation()));
+            ret.last()->appendUniform(Uniform1f::create(m_blurAmountLocation[1]
+                , 1.0f / float(surface->size().width())));
+
+            // Repaint original image
+            ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough));
+            ret.last()->setPopSnapshot();
+            }
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+
+    if (ret.size() % 2) // We need an even number of actions. See ping-pong note in applyLayerFilters().
+        ret.append(LayerFilterRendererAction::create(LayerData::CSSFilterShaderPassthrough));
+
+    return ret;
+}
+
+static float texcoords[4 * 2] = { 0, 0,  0, 1,  1, 1,  1, 0 };
+
+void LayerFilterRenderer::applyActions(unsigned& fbo, LayerCompositingThread* layer, Vector<RefPtr<LayerFilterRendererAction> > actions)
+{
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+    ASSERT(!(actions.size() % 2)); // See ping-ponging note below.
+
+    if (!m_enabled)
+        return;
+
+    if (!layer->filters().size())
+        return;
+
+    if (!m_texture)
+        m_texture = textureCacheCompositingThread()->createTexture();
+
+    bool requireSnapshot = false;
+    for (unsigned i = 0; i < actions.size(); ++i) {
+        if (actions[i]->shouldPushSnapshot())
+            requireSnapshot = true;
+    }
+
+    if (!m_snapshotTexture && requireSnapshot)
+        m_snapshotTexture = textureCacheCompositingThread()->createTexture();
+
+    LayerRendererSurface* surface = layer->layerRendererSurface();
+
+    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, &layer->getTransformedBounds() );
+    glVertexAttribPointer(m_texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
+
+    m_texture->protect(surface->texture()->size());
+    if (requireSnapshot)
+        m_snapshotTexture->protect(surface->texture()->size());
+
+    if (!fbo)
+        glGenFramebuffers(1, &fbo);
+
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+    for (unsigned int i = 0; i < actions.size(); ++i) {
+        // NOTE ABOUT PING-PONGING
+        // =======================
+        // Under OpenGL ES 2.0, we cannot use the fbo we are writting to as a texture, so we need to play ping-pong:
+        //  1) Draw parent surface to our texture with effect.
+        //  2) Draw our surface to parent texture with effect.
+        //  3) Repeat.
+        // Because we eventually have to end on the parent texture, we need an even number of actions.
+        // actionsForOperations takes care of that.
+
+        if (actions[i]->shouldPushSnapshot())
+            pushSnapshot(surface, (!(i % 2) ? surface->texture()->textureId() : m_texture->textureId()));
+
+        if (!(i % 2))
+            ping(surface); // Set framebuffer to ours, and texture to parent
+        else
+            pong(surface); // Set texture to parent, and framebuffer to us
+
+        glClear(GL_COLOR_BUFFER_BIT); // to transparency
+        glViewport(0, 0, surface->size().width(), surface->size().height());
+
+        actions[i]->useActionOn(this);
+
+        if (actions[i]->shouldPopSnapshot())
+            popSnapshot();
+
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+    }
+
+    m_texture->unprotect();
+    if (requireSnapshot)
+        m_snapshotTexture->unprotect();
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+} // namespace WebCore
+
+#endif // USE(ACCELERATED_COMPOSITING) && USE(CSS_FILTERS)
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerFilterRenderer.h b/Source/WebCore/platform/graphics/blackberry/LayerFilterRenderer.h
new file mode 100644
index 0000000..1c1f06e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/blackberry/LayerFilterRenderer.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef LayerFilterRenderer_h
+#define LayerFilterRenderer_h
+
+#if USE(ACCELERATED_COMPOSITING) && ENABLE(CSS_FILTERS)
+
+#include "IntRect.h"
+#include "LayerData.h"
+#include "OwnPtr.h"
+#include "Texture.h"
+#include "TransformationMatrix.h"
+
+#include <BlackBerryPlatformGLES2Context.h>
+#include <BlackBerryPlatformIntRectRegion.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class LayerCompositingThread;
+class LayerFilterRenderer;
+class LayerFilterRendererAction;
+class LayerRendererSurface;
+
+class Uniformf : public RefCounted<Uniformf> {
+    WTF_MAKE_NONCOPYABLE(Uniformf);
+public:
+    virtual void apply() = 0;
+
+protected:
+    Uniformf(int location);
+    const int& location() const { return m_location; }
+
+private:
+    int m_location;
+};
+
+class Uniform1f : public Uniformf {
+public:
+    static PassRefPtr<Uniformf> create(int location, float val);
+
+protected:
+    Uniform1f(int location, float val);
+
+private:
+    virtual void apply();
+    float m_val;
+};
+
+class Uniform2f : public Uniformf {
+public:
+    static PassRefPtr<Uniformf> create(int location, float val0, float val1);
+
+protected:
+    Uniform2f(int location, float val0, float val1);
+
+private:
+    virtual void apply();
+    float m_val[2];
+};
+
+class Uniform3f : public Uniformf {
+public:
+    static PassRefPtr<Uniformf> create(int location, float val0, float val1, float val2);
+
+protected:
+    Uniform3f(int location, float val0, float val1, float val2);
+
+private:
+    virtual void apply();
+    float m_val[3];
+};
+
+class LayerFilterRendererAction : public RefCounted<LayerFilterRendererAction> {
+public:
+    static PassRefPtr<LayerFilterRendererAction> create(int programId);
+        // A vector of actions must have an even count, so if you have an odd count, add a passthrough event at the end.
+        // See the ping-pong note in LayerFilterRenderer::applyActions.
+    ~LayerFilterRendererAction();
+
+    bool shouldPushSnapshot() const { return m_pushSnapshot; }
+    void setPushSnapshot() { m_pushSnapshot = true; }
+
+    bool shouldPopSnapshot() const { return m_popSnapshot; }
+    void setPopSnapshot() { m_popSnapshot = true; }
+
+    void appendUniform(const RefPtr<Uniformf>& uniform) { m_uniforms.append(uniform); }
+    void useActionOn(LayerFilterRenderer*);
+
+protected:
+    int m_programId;
+    bool m_pushSnapshot;
+    bool m_popSnapshot;
+
+    Vector<RefPtr<Uniformf> > m_uniforms;
+private:
+    LayerFilterRendererAction(int programId);
+};
+
+class LayerFilterRenderer {
+    WTF_MAKE_NONCOPYABLE(LayerFilterRenderer);
+
+public:
+    static PassOwnPtr<LayerFilterRenderer> create(const int& positionLocation, const int& texCoordLocation);
+    void applyActions(unsigned& fbo, LayerCompositingThread*, Vector<RefPtr<LayerFilterRendererAction> >);
+    Vector<RefPtr<LayerFilterRendererAction> > actionsForOperations(LayerRendererSurface*, const Vector<RefPtr<FilterOperation> >&);
+
+    // If initialization fails, or disable() is called, this is false.
+    bool isEnabled() const { return m_enabled; }
+    void disable() { m_enabled = false; }
+
+private:
+    LayerFilterRenderer(const int& positionLocation, const int& texCoordLocation);
+    void bindCommonAttribLocation(int location, const char* attribName);
+    bool initializeSharedGLObjects();
+
+    // See note about ping-ponging in applyActions()
+    void ping(LayerRendererSurface*);
+    void pong(LayerRendererSurface*);
+
+    // This is for shadows, where we need to create a shadow, and then repaint the original image
+    // on top of the shadow.
+    void pushSnapshot(LayerRendererSurface*, int sourceId);
+    void popSnapshot();
+
+    bool m_enabled;
+
+    // ESSL attributes shared with LayerRenderer - see constructor:
+    const int m_positionLocation;
+    const int m_texCoordLocation;
+
+    // ESSL program object IDs:
+    unsigned m_cssFilterProgramObject[LayerData::NumberOfCSSFilterShaders];
+
+    // ESSL uniform locations:
+    int m_amountLocation[LayerData::NumberOfCSSFilterShaders];
+    int m_blurAmountLocation[2]; // 0 = Y, 1 = X
+    int m_shadowColorLocation;
+    int m_offsetLocation;
+
+    // Textures for playing ping-pong - see note in applyActions()
+    RefPtr<Texture> m_texture;
+    RefPtr<Texture> m_snapshotTexture;
+
+    friend class LayerFilterRendererAction;
+};
+
+}
+
+#endif // USE(ACCELERATED_COMPOSITING) && ENABLE(CSS_FILTERS)
+
+#endif // LayerFilterRenderer_h
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerRenderer.cpp b/Source/WebCore/platform/graphics/blackberry/LayerRenderer.cpp
index 77623e5..0e42dd4 100644
--- a/Source/WebCore/platform/graphics/blackberry/LayerRenderer.cpp
+++ b/Source/WebCore/platform/graphics/blackberry/LayerRenderer.cpp
@@ -37,6 +37,7 @@
 #include "LayerRenderer.h"
 
 #include "LayerCompositingThread.h"
+#include "LayerFilterRenderer.h"
 #include "PlatformString.h"
 #include "TextureCacheCompositingThread.h"
 
@@ -64,7 +65,7 @@
 #endif
 }
 
-static GLuint loadShader(GLenum type, const char* shaderSource)
+GLuint LayerRenderer::loadShader(GLenum type, const char* shaderSource)
 {
     GLuint shader = glCreateShader(type);
     if (!shader)
@@ -86,7 +87,7 @@
     return shader;
 }
 
-static GLuint loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
+GLuint LayerRenderer::loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource)
 {
     GLuint vertexShader;
     GLuint fragmentShader;
@@ -500,6 +501,17 @@
         int currentStencilValue = 0;
         FloatRect clipRect(-1, -1, 2, 2);
         compositeLayersRecursive(surfaceLayers[i].get(), currentStencilValue, clipRect);
+
+#if ENABLE(CSS_FILTERS)
+        if (!m_filterRenderer)
+            m_filterRenderer = LayerFilterRenderer::create(m_positionLocation, m_texCoordLocation);
+        if (layer->filterOperationsChanged()) {
+            layer->setFilterOperationsChanged(false);
+            layer->setFilterActions(m_filterRenderer->actionsForOperations(surface, layer->filters().operations()));
+        }
+        m_filterRenderer->applyActions(m_fbo, layer, layer->filterActions());
+        glClearColor(0, 0, 0, 0);
+#endif
     }
 
     // If there are layers drawed on surfaces, we need to switch to default framebuffer.
@@ -712,7 +724,11 @@
     // Calculate the layer's opacity.
     opacity *= layer->opacity();
 
+#if ENABLE(CSS_FILTERS)
+    bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer() || layer->filters().size();
+#else
     bool useLayerRendererSurface = layer->maskLayer() || layer->replicaLayer();
+#endif
     if (!useLayerRendererSurface) {
         layer->setDrawOpacity(opacity);
         layer->clearLayerRendererSurface();
@@ -984,7 +1000,7 @@
     return m_context->makeCurrent();
 }
 
-// Binds the given attribute name to a common location across all three programs
+// Binds the given attribute name to a common location across all programs
 // used by the compositor. This allows the code to bind the attributes only once
 // even when switching between programs.
 void LayerRenderer::bindCommonAttribLocation(int location, const char* attribName)
@@ -1053,7 +1069,6 @@
         "  gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha * maskColor.w;         \n"
         "}                                                               \n";
 
-
     // Shaders for drawing the debug borders around the layers.
     char colorVertexShaderString[] =
         "attribute vec4 a_position;   \n"
@@ -1139,7 +1154,7 @@
         return false;
     }
 
-    // Specify the attrib location for the position and make it the same for all three programs to
+    // Specify the attrib location for the position and make it the same for all programs to
     // avoid binding re-binding the vertex attributes.
     bindCommonAttribLocation(m_positionLocation, "a_position");
     bindCommonAttribLocation(m_texCoordLocation, "a_texCoord");
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerRenderer.h b/Source/WebCore/platform/graphics/blackberry/LayerRenderer.h
index f6c3be8..437927b 100644
--- a/Source/WebCore/platform/graphics/blackberry/LayerRenderer.h
+++ b/Source/WebCore/platform/graphics/blackberry/LayerRenderer.h
@@ -37,6 +37,7 @@
 
 #include "IntRect.h"
 #include "LayerData.h"
+#include "LayerFilterRenderer.h"
 #include "TransformationMatrix.h"
 
 #include <BlackBerryPlatformGLES2Context.h>
@@ -134,6 +135,9 @@
     // If the layer has already been drawed on a surface.
     bool layerAlreadyOnSurface(LayerCompositingThread*) const;
 
+    static GLuint loadShader(GLenum type, const char* shaderSource);
+    static GLuint loadShaderProgram(const char* vertexShaderSource, const char* fragmentShaderSource);
+
 private:
     void prepareFrameRecursive(LayerCompositingThread*, double animationTime, bool isContextCurrent);
     void updateLayersRecursive(LayerCompositingThread*, const TransformationMatrix& parentMatrix, Vector<RefPtr<LayerCompositingThread> >& surfaceLayers, float opacity, FloatRect clipRect);
@@ -164,6 +168,10 @@
     // Shader uniform and attribute locations.
     const int m_positionLocation;
     const int m_texCoordLocation;
+#if ENABLE(CSS_FILTERS)
+    OwnPtr<LayerFilterRenderer> m_filterRenderer;
+#endif
+
     int m_samplerLocation[LayerData::NumberOfLayerProgramShaders];
     int m_alphaLocation[LayerData::NumberOfLayerProgramShaders];
     int m_maskSamplerLocation[LayerData::NumberOfLayerProgramShaders];
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.cpp b/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.cpp
index 15bbe0a..e9d3dff 100644
--- a/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.cpp
+++ b/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.cpp
@@ -65,6 +65,9 @@
     , m_isMask(false)
     , m_animationsChanged(false)
     , m_clearOverrideOnCommit(false)
+#if ENABLE(CSS_FILTERS)
+    , m_filtersChanged(false)
+#endif
 {
     if (type == Layer)
         m_tiler = LayerTiler::create(this);
@@ -284,6 +287,12 @@
     m_position += m_absoluteOffset;
     // Copy the base variables from this object into m_layerCompositingThread
     replicate(m_layerCompositingThread.get());
+#if ENABLE(CSS_FILTERS)
+    if (m_filtersChanged) {
+        m_filtersChanged = false;
+        m_layerCompositingThread->setFilterOperationsChanged(true);
+    }
+#endif
     if (m_animationsChanged) {
         m_layerCompositingThread->setRunningAnimations(m_runningAnimations);
         m_layerCompositingThread->setSuspendedAnimations(m_suspendedAnimations);
@@ -405,6 +414,31 @@
     setNeedsDisplay();
 }
 
+#if ENABLE(CSS_FILTERS)
+bool LayerWebKitThread::filtersCanBeComposited(const FilterOperations& filters)
+{
+    // There is work associated with compositing filters, even if there are zero filters,
+    // so if there are no filters, claim we can't composite them.
+    if (!filters.size())
+        return false;
+
+    for (unsigned i = 0; i < filters.size(); ++i) {
+        const FilterOperation* filterOperation = filters.at(i);
+        switch (filterOperation->getOperationType()) {
+        case FilterOperation::REFERENCE:
+#if ENABLE(CSS_SHADERS)
+        case FilterOperation::CUSTOM:
+#endif
+            return false;
+        default:
+            break;
+        }
+    }
+
+    return true;
+}
+#endif
+
 const LayerWebKitThread* LayerWebKitThread::rootLayer() const
 {
     const LayerWebKitThread* layer = this;
diff --git a/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.h b/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.h
index 49a49be..e1a9254 100644
--- a/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.h
+++ b/Source/WebCore/platform/graphics/blackberry/LayerWebKitThread.h
@@ -98,6 +98,11 @@
 
     void setOpacity(float opacity) { m_opacity = opacity; setNeedsCommit(); }
 
+#if ENABLE(CSS_FILTERS)
+    void setFilters(const FilterOperations& filters) { m_filters = filters; m_filtersChanged = true; setNeedsCommit(); }
+    static bool filtersCanBeComposited(const FilterOperations& filters);
+#endif
+
     void setOpaque(bool isOpaque) { m_isOpaque = isOpaque; setNeedsCommit(); }
 
     void setPosition(const FloatPoint& position) { m_position = position; setNeedsCommit(); }
@@ -202,6 +207,9 @@
     unsigned m_isMask : 1;
     unsigned m_animationsChanged : 1;
     unsigned m_clearOverrideOnCommit : 1;
+#if ENABLE(CSS_FILTERS)
+    unsigned m_filtersChanged : 1;
+#endif
 };
 
 }
diff --git a/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp b/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp
index 36d06d3..48aba2b 100644
--- a/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp
+++ b/Source/WebCore/platform/graphics/filters/FECustomFilter.cpp
@@ -41,6 +41,7 @@
 #include "DrawingBuffer.h"
 #include "GraphicsContext3D.h"
 #include "ImageData.h"
+#include "NotImplemented.h"
 #include "RenderTreeAsText.h"
 #include "TextStream.h"
 #include "Texture.h"
@@ -139,9 +140,11 @@
     if (!hadContext || m_contextSize != newContextSize)
         resizeContext(newContextSize);
 
+#if !PLATFORM(BLACKBERRY) // BlackBerry defines its own Texture class.
     // Do not draw the filter if the input image cannot fit inside a single GPU texture.
     if (m_inputTexture->tiles().numTilesX() != 1 || m_inputTexture->tiles().numTilesY() != 1)
         return;
+#endif
     
     // The shader had compiler errors. We cannot draw anything.
     if (!m_compiledProgram->isInitialized())
@@ -185,7 +188,11 @@
 
 void FECustomFilter::resizeContext(const IntSize& newContextSize)
 {
+#if !PLATFORM(BLACKBERRY) // BlackBerry defines its own Texture class
     m_inputTexture = Texture::create(m_context.get(), Texture::RGBA8, newContextSize.width(), newContextSize.height());
+#else
+    m_inputTexture = Texture::create(true);
+#endif
     
     if (!m_frameBuffer)
         m_frameBuffer = m_context->createFramebuffer();
@@ -269,8 +276,12 @@
     if (m_compiledProgram->samplerLocation() != -1) {
         m_context->activeTexture(GraphicsContext3D::TEXTURE0);
         m_context->uniform1i(m_compiledProgram->samplerLocation(), 0);
+#if !PLATFORM(BLACKBERRY)
         m_inputTexture->load(srcPixelArray->data());
         m_inputTexture->bindTile(0);
+#else
+        notImplemented();
+#endif
     }
     
     if (m_compiledProgram->projectionMatrixLocation() != -1) {
diff --git a/Source/WebCore/platform/graphics/filters/FilterOperation.h b/Source/WebCore/platform/graphics/filters/FilterOperation.h
index 2a4f08a..e72600c 100644
--- a/Source/WebCore/platform/graphics/filters/FilterOperation.h
+++ b/Source/WebCore/platform/graphics/filters/FilterOperation.h
@@ -35,6 +35,10 @@
 #include <wtf/RefCounted.h>
 #include <wtf/text/WTFString.h>
 
+#if PLATFORM(BLACKBERRY)
+#include <wtf/ThreadSafeRefCounted.h>
+#endif
+
 // Annoyingly, wingdi.h #defines this.
 #ifdef PASSTHROUGH
 #undef PASSTHROUGH
@@ -44,7 +48,11 @@
 
 // CSS Filters
 
+#if PLATFORM(BLACKBERRY)
+class FilterOperation : public ThreadSafeRefCounted<FilterOperation> {
+#else
 class FilterOperation : public RefCounted<FilterOperation> {
+#endif
 public:
     enum OperationType {
         REFERENCE, // url(#somefilter)
diff --git a/Source/cmake/OptionsBlackBerry.cmake b/Source/cmake/OptionsBlackBerry.cmake
index af18cc1..197d10e 100644
--- a/Source/cmake/OptionsBlackBerry.cmake
+++ b/Source/cmake/OptionsBlackBerry.cmake
@@ -173,9 +173,15 @@
 
 IF (ENABLE_GLES2)
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_3D_RENDERING ON)
+    WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ACCELERATED_2D_CANVAS ON)
+    WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_FILTERS ON)
+    WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_SHADERS ON)
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBGL ON)
 ELSE ()
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_3D_RENDERING OFF)
+    WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_ACCELERATED_2D_CANVAS OFF)
+    WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_FILTERS OFF)
+    WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_SHADERS OFF)
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBGL OFF)
 ENDIF ()
 
diff --git a/Source/cmakeconfig.h.cmake b/Source/cmakeconfig.h.cmake
index e256b0e..b246291 100644
--- a/Source/cmakeconfig.h.cmake
+++ b/Source/cmakeconfig.h.cmake
@@ -25,6 +25,8 @@
 #cmakedefine01 ENABLE_CSS_STICKY_POSITION
 #cmakedefine01 ENABLE_CSS_VARIABLES
 #cmakedefine01 ENABLE_CSS3_FLEXBOX
+#cmakedefine01 ENABLE_CSS_FILTERS
+#cmakedefine01 ENABLE_CSS_SHADERS
 #cmakedefine01 ENABLE_CUSTOM_SCHEME_HANDLER
 #cmakedefine01 ENABLE_DATALIST_ELEMENT
 #cmakedefine01 ENABLE_DATA_TRANSFER_ITEMS
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index f177714..62a1222 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,16 @@
+2012-07-31  Joshua Netterfield  <jnetterfield@rim.com>
+
+        [BlackBerry] Enable CSS Filter Effects
+        https://bugs.webkit.org/show_bug.cgi?id=92685
+
+        Reviewed by Rob Buis.
+
+        Enable CSS filter effects, with the exception of custom effects (CSS shaders) and reference effects (SVG effects)
+
+        Internally reviewed by Arvid Nilsson <anilsson@rim.com> and Antonio Gomes <agomes@rim.com>.
+
+        * Scripts/webkitperl/FeatureList.pm: Acknowledge CSS filter effects.
+
 2012-07-31  Dirk Pranke  <dpranke@chromium.org>
 
         nrwt: clean up prepare_lists_and_print_output, run, set_up_run a bit
diff --git a/Tools/Scripts/webkitperl/FeatureList.pm b/Tools/Scripts/webkitperl/FeatureList.pm
index 77cc1f7..344509f 100644
--- a/Tools/Scripts/webkitperl/FeatureList.pm
+++ b/Tools/Scripts/webkitperl/FeatureList.pm
@@ -163,7 +163,7 @@
       define => "ENABLE_CSS_EXCLUSIONS", default => 1, value => \$cssExclusionsSupport },
 
     { option => "css-filters", desc => "Toggle CSS Filters support",
-      define => "ENABLE_CSS_FILTERS", default => isAppleWebKit(), value => \$cssFiltersSupport },
+      define => "ENABLE_CSS_FILTERS", default => isAppleWebKit() || isBlackBerry(), value => \$cssFiltersSupport },
 
     { option => "css3-flexbox", desc => "Toggle CSS3 Flexbox support",
       define => "ENABLE_CSS3_FLEXBOX", default => 1, value => \$css3FlexboxSupport },