Backed out 10 changesets (bug 1505871) for wrench bustages CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Tue, 26 Feb 2019 03:43:12 +0200
changeset 461110 3c030119c0dcf447dd1afe7165b2d6846a0bc7f0
parent 461109 045ab0ec361396705590c5bbcc93e828481ae4e3
child 461111 c04aa3d7aa8e46bd547d8e0e1a1ac7a88ae3e4c4
push id35618
push usershindli@mozilla.com
push dateTue, 26 Feb 2019 16:54:44 +0000
treeherdermozilla-central@d326a9d5f77b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1505871
milestone67.0a1
backs out045ab0ec361396705590c5bbcc93e828481ae4e3
6486435a048dba1d6bfb5fbc6442c0cce2350332
9be871042749e932076d769de91a01bfbd696796
0007feaf988dca3eee682aa1f288209ea8cb3095
3cb8fb01e77e49e12290dc3b92c404da7435a11e
2fff213d97e3d9830b28bcc1c053ff6abf83ba46
1ad20d485eca142b1c10fc640fe8240b95f2cffe
0fd8742fa66223b490880d6b759066d1e5532148
1899600a79855a892c9ec75216db20ad5e2b0c2e
f9578d20e54ec0c0ffebe29d78946352cc9ae438
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 10 changesets (bug 1505871) for wrench bustages CLOSED TREE Backed out changeset 045ab0ec3613 (bug 1505871) Backed out changeset 6486435a048d (bug 1505871) Backed out changeset 9be871042749 (bug 1505871) Backed out changeset 0007feaf988d (bug 1505871) Backed out changeset 3cb8fb01e77e (bug 1505871) Backed out changeset 2fff213d97e3 (bug 1505871) Backed out changeset 1ad20d485eca (bug 1505871) Backed out changeset 0fd8742fa662 (bug 1505871) Backed out changeset 1899600a7985 (bug 1505871) Backed out changeset f9578d20e54e (bug 1505871)
gfx/layers/wr/StackingContextHelper.h
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/layers/wr/WebRenderCommandBuilder.h
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
gfx/wr/examples/animation.rs
gfx/wr/webrender/res/brush_blend.glsl
gfx/wr/webrender/res/gpu_cache.glsl
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/display_list_flattener.rs
gfx/wr/webrender/src/filterdata.rs
gfx/wr/webrender/src/intern_types.rs
gfx/wr/webrender/src/lib.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/prim_store/mod.rs
gfx/wr/webrender/src/prim_store/picture.rs
gfx/wr/webrender/src/profiler.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/scene.rs
gfx/wr/webrender/src/tiling.rs
gfx/wr/webrender_api/src/api.rs
gfx/wr/webrender_api/src/display_item.rs
gfx/wr/webrender_api/src/display_list.rs
gfx/wr/wrench/reftests/filters/filter-component-transfer-ref.yaml
gfx/wr/wrench/reftests/filters/filter-component-transfer.yaml
gfx/wr/wrench/reftests/filters/reftest.list
gfx/wr/wrench/src/yaml_frame_reader.rs
gfx/wr/wrench/src/yaml_frame_writer.rs
gfx/wr/wrench/src/yaml_helper.rs
layout/base/PresShell.cpp
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/svg/nsFilterInstance.cpp
layout/svg/nsFilterInstance.h
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGIntegrationUtils.h
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -7,17 +7,16 @@
 #ifndef GFX_STACKINGCONTEXTHELPER_H
 #define GFX_STACKINGCONTEXTHELPER_H
 
 #include "mozilla/Attributes.h"
 #include "mozilla/gfx/MatrixFwd.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "Units.h"
-#include "nsSVGIntegrationUtils.h" // for WrFiltersHolder
 
 class nsDisplayTransform;
 
 namespace mozilla {
 
 struct ActiveScrolledRoot;
 
 namespace layers {
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1420,17 +1420,17 @@ void WebRenderCommandBuilder::EmptyTrans
 bool WebRenderCommandBuilder::NeedsEmptyTransaction() {
   return !mLastCanvasDatas.IsEmpty();
 }
 
 void WebRenderCommandBuilder::BuildWebRenderCommands(
     wr::DisplayListBuilder& aBuilder,
     wr::IpcResourceUpdateQueue& aResourceUpdates, nsDisplayList* aDisplayList,
     nsDisplayListBuilder* aDisplayListBuilder, WebRenderScrollData& aScrollData,
-    wr::LayoutSize& aContentSize, WrFiltersHolder&& aFilters) {
+    wr::LayoutSize& aContentSize, nsTArray<wr::FilterOp>&& aFilters) {
   AUTO_PROFILER_LABEL_CATEGORY_PAIR(GRAPHICS_WRDisplayList);
 
   StackingContextHelper sc;
   aScrollData = WebRenderScrollData(mManager);
   MOZ_ASSERT(mLayerScrollData.empty());
   mLastCanvasDatas.Clear();
   mLastAsr = nullptr;
   mBuilderDumpIndex = 0;
@@ -1446,18 +1446,17 @@ void WebRenderCommandBuilder::BuildWebRe
     }
 
     nsPresContext* presContext =
         aDisplayListBuilder->RootReferenceFrame()->PresContext();
     bool isTopLevelContent =
         presContext->Document()->IsTopLevelContentDocument();
 
     wr::StackingContextParams params;
-    params.mFilters = std::move(aFilters.filters);
-    params.mFilterDatas = std::move(aFilters.filter_datas);
+    params.mFilters = std::move(aFilters);
     params.animation = mZoomProp.ptrOr(nullptr);
     params.cache_tiles = isTopLevelContent;
     params.clip =
         wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
 
     StackingContextHelper pageRootSc(sc, nullptr, nullptr, nullptr, aBuilder,
                                      params);
     if (ShouldDumpDisplayList(aDisplayListBuilder)) {
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -52,17 +52,17 @@ class WebRenderCommandBuilder {
   bool NeedsEmptyTransaction();
 
   void BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                               wr::IpcResourceUpdateQueue& aResourceUpdates,
                               nsDisplayList* aDisplayList,
                               nsDisplayListBuilder* aDisplayListBuilder,
                               WebRenderScrollData& aScrollData,
                               wr::LayoutSize& aContentSize,
-                              WrFiltersHolder&& aFilters);
+                              nsTArray<wr::FilterOp>&& aFilters);
 
   void PushOverrideForASR(const ActiveScrolledRoot* aASR,
                           const wr::WrSpatialId& aSpatialId);
   void PopOverrideForASR(const ActiveScrolledRoot* aASR);
 
   Maybe<wr::ImageKey> CreateImageKey(
       nsDisplayItem* aItem, ImageContainer* aContainer,
       mozilla::wr::DisplayListBuilder& aBuilder,
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -241,17 +241,17 @@ void WebRenderLayerManager::EndTransacti
                                            EndTransactionFlags aFlags) {
   // This should never get called, all callers should use
   // EndTransactionWithoutLayer instead.
   MOZ_ASSERT(false);
 }
 
 void WebRenderLayerManager::EndTransactionWithoutLayer(
     nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
-    WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground) {
+    nsTArray<wr::FilterOp>&& aFilters, WebRenderBackgroundData* aBackground) {
   AUTO_PROFILER_TRACING("Paint", "RenderLayers", GRAPHICS);
 
   // Since we don't do repeat transactions right now, just set the time
   mAnimationReadyTime = TimeStamp::Now();
 
   WrBridge()->BeginTransaction();
 
   LayoutDeviceIntSize size = mWidget->GetClientSize();
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -74,17 +74,17 @@ class WebRenderLayerManager final : publ
 
   virtual bool BeginTransactionWithTarget(gfxContext* aTarget,
                                           const nsCString& aURL) override;
   virtual bool BeginTransaction(const nsCString& aURL) override;
   virtual bool EndEmptyTransaction(
       EndTransactionFlags aFlags = END_DEFAULT) override;
   void EndTransactionWithoutLayer(
       nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
-      WrFiltersHolder&& aFilters = WrFiltersHolder(),
+      nsTArray<wr::FilterOp>&& aFilters = nsTArray<wr::FilterOp>(),
       WebRenderBackgroundData* aBackground = nullptr);
   virtual void EndTransaction(
       DrawPaintedLayerCallback aCallback, void* aCallbackData,
       EndTransactionFlags aFlags = END_DEFAULT) override;
 
   virtual LayersBackend GetBackendType() override {
     return LayersBackend::LAYERS_WR;
   }
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -685,17 +685,17 @@ Maybe<wr::WrSpatialId> DisplayListBuilde
   const wr::LayoutTransform* maybeTransform = transform ? &matrix : nullptr;
   WRDL_LOG("PushStackingContext b=%s t=%s\n", mWrState,
            Stringify(aBounds).c_str(),
            transform ? Stringify(*transform).c_str() : "none");
 
   auto spatialId = wr_dp_push_stacking_context(
       mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aParams,
       maybeTransform, aParams.mFilters.Elements(), aParams.mFilters.Length(),
-      aParams.mFilterDatas.Elements(), aParams.mFilterDatas.Length(), aRasterSpace);
+      aRasterSpace);
 
   return spatialId.id != 0 ? Some(spatialId) : Nothing();
 }
 
 void DisplayListBuilder::PopStackingContext(bool aIsReferenceFrame) {
   WRDL_LOG("PopStackingContext\n", mWrState);
   wr_dp_pop_stacking_context(mWrState, aIsReferenceFrame);
 }
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -324,17 +324,16 @@ struct MOZ_STACK_CLASS StackingContextPa
                                 wr::MixBlendMode::Normal} {}
 
   void SetPreserve3D(bool aPreserve) {
     transform_style =
         aPreserve ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat;
   }
 
   nsTArray<wr::FilterOp> mFilters;
-  nsTArray<wr::WrFilterData> mFilterDatas;
   wr::LayoutRect mBounds = wr::ToLayoutRect(LayoutDeviceRect());
   const gfx::Matrix4x4* mBoundTransform = nullptr;
   const gfx::Matrix4x4* mTransformPtr = nullptr;
   Maybe<nsDisplayTransform*> mDeferredTransformItem;
   // Whether the stacking context is possibly animated. This alters how
   // coordinates are transformed/snapped to invalidate less when transforms
   // change frequently.
   bool mAnimated = false;
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -8,17 +8,17 @@ use std::os::unix::ffi::OsStringExt;
 use std::io::Cursor;
 use std::{mem, slice, ptr, env};
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::cell::RefCell;
 use std::sync::Arc;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::ops::Range;
-use std::os::raw::{c_void, c_char, c_float};
+use std::os::raw::{c_void, c_char};
 #[cfg(target_os = "android")]
 use std::os::raw::{c_int};
 use gleam::gl;
 
 use webrender::api::*;
 use webrender::{ReadPixelsFormat, Renderer, RendererOptions, RendererStats, ThreadListener};
 use webrender::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::DebugFlags;
@@ -484,34 +484,16 @@ impl ExternalImageHandler for WrExternal
               id: ExternalImageId,
               channel_index: u8) {
         unsafe {
             (self.unlock_func)(self.external_image_obj, id.into(), channel_index);
         }
     }
 }
 
-#[repr(C)]
-#[derive(Clone, Copy)]
-// Used for ComponentTransfer only
-pub struct WrFilterData {
-    funcR_type: ComponentTransferFuncType,
-    R_values: *mut c_float,
-    R_values_count: usize,
-    funcG_type: ComponentTransferFuncType,
-    G_values: *mut c_float,
-    G_values_count: usize,
-    funcB_type: ComponentTransferFuncType,
-    B_values: *mut c_float,
-    B_values_count: usize,
-    funcA_type: ComponentTransferFuncType,
-    A_values: *mut c_float,
-    A_values_count: usize,
-}
-
 #[repr(u32)]
 pub enum WrAnimationType {
     Transform = 0,
     Opacity = 1,
 }
 
 #[repr(C)]
 pub struct WrAnimationProperty {
@@ -1965,41 +1947,25 @@ pub struct WrStackingContextParams {
 pub extern "C" fn wr_dp_push_stacking_context(
     state: &mut WrState,
     mut bounds: LayoutRect,
     spatial_id: WrSpatialId,
     params: &WrStackingContextParams,
     transform: *const LayoutTransform,
     filters: *const FilterOp,
     filter_count: usize,
-    filter_datas: *const WrFilterData,
-    filter_datas_count: usize,
     glyph_raster_space: RasterSpace,
 ) -> WrSpatialId {
     debug_assert!(unsafe { !is_in_render_thread() });
 
     let c_filters = make_slice(filters, filter_count);
     let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
                                                            *c_filter
     }).collect();
 
-    let c_filter_datas = make_slice(filter_datas, filter_datas_count);
-    let r_filter_datas : Vec<FilterData> = c_filter_datas.iter().map(|c_filter_data| {
-        FilterData {
-            func_r_type: c_filter_data.funcR_type,
-            r_values: make_slice(c_filter_data.R_values, c_filter_data.R_values_count).to_vec(),
-            func_g_type: c_filter_data.funcG_type,
-            g_values: make_slice(c_filter_data.G_values, c_filter_data.G_values_count).to_vec(),
-            func_b_type: c_filter_data.funcB_type,
-            b_values: make_slice(c_filter_data.B_values, c_filter_data.B_values_count).to_vec(),
-            func_a_type: c_filter_data.funcA_type,
-            a_values: make_slice(c_filter_data.A_values, c_filter_data.A_values_count).to_vec(),
-        }
-    }).collect();
-
     let transform_ref = unsafe { transform.as_ref() };
     let mut transform_binding = match transform_ref {
         Some(t) => Some(PropertyBinding::Value(t.clone())),
         None => None,
     };
 
     let opacity_ref = unsafe { params.opacity.as_ref() };
     let mut has_opacity_animation = false;
@@ -2077,17 +2043,16 @@ pub extern "C" fn wr_dp_push_stacking_co
     state.frame_builder
          .dl_builder
          .push_stacking_context(&prim_info,
                                 wr_spatial_id,
                                 wr_clip_id,
                                 params.transform_style,
                                 params.mix_blend_mode,
                                 &filters,
-                                &r_filter_datas,
                                 glyph_raster_space,
                                 params.cache_tiles);
 
     result
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState,
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -42,19 +42,17 @@ void gecko_profiler_end_marker(const cha
   macro(normal_border);                    \
   macro(image_border);                     \
   macro(image);                            \
   macro(yuv_image);                        \
   macro(line_decoration);                  \
   macro(linear_grad);                      \
   macro(radial_grad);                      \
   macro(picture);                          \
-  macro(text_run);                         \
-  macro(filterdata);
-
+  macro(text_run);
 
 // Prelude of types necessary before including webrender_ffi_generated.h
 namespace mozilla {
 namespace wr {
 
 // Because this struct is macro-generated on the Rust side, cbindgen can't see
 // it. Work around that by re-declaring it here.
 #define DECLARE_MEMBER(id) uintptr_t id;
--- a/gfx/wr/examples/animation.rs
+++ b/gfx/wr/examples/animation.rs
@@ -62,17 +62,16 @@ impl App {
             PropertyBinding::Binding(property_key, LayoutTransform::identity()),
             ReferenceFrameKind::Transform,
         );
 
         builder.push_simple_stacking_context_with_filters(
             &LayoutPrimitiveInfo::new(LayoutRect::zero()),
             spatial_id,
             &filters,
-            &[],
         );
 
         let space_and_clip = SpaceAndClipInfo {
             spatial_id,
             clip_id: ClipId::root(pipeline_id),
         };
         let clip_bounds = LayoutRect::new(LayoutPoint::zero(), bounds.size);
         let complex_clip = ComplexClipRegion {
--- a/gfx/wr/webrender/res/brush_blend.glsl
+++ b/gfx/wr/webrender/res/brush_blend.glsl
@@ -1,34 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define VECS_PER_SPECIFIC_BRUSH 3
 
-#define COMPONENT_TRANSFER_IDENTITY 0
-#define COMPONENT_TRANSFER_TABLE 1
-#define COMPONENT_TRANSFER_DISCRETE 2
-#define COMPONENT_TRANSFER_LINEAR 3
-#define COMPONENT_TRANSFER_GAMMA 4
-
 #include shared,prim_shared,brush
 
 // Interpolated UV coordinates to sample.
 varying vec2 vUv;
 
 // X = layer index to sample, Y = flag to allow perspective interpolation of UV.
 flat varying vec2 vLayerAndPerspective;
 flat varying float vAmount;
 flat varying int vOp;
 flat varying mat3 vColorMat;
 flat varying vec3 vColorOffset;
 flat varying vec4 vUvClipBounds;
-flat varying int vTableAddress;
-flat varying int vFuncs[4];
 
 #ifdef WR_VERTEX_SHADER
 
 void brush_vs(
     VertexInfo vi,
     int prim_address,
     RectWithSize local_rect,
     RectWithSize segment_rect,
@@ -58,29 +50,19 @@ void brush_vs(
     float lumB = 0.0722;
     float oneMinusLumR = 1.0 - lumR;
     float oneMinusLumG = 1.0 - lumG;
     float oneMinusLumB = 1.0 - lumB;
 
     float amount = float(user_data.z) / 65536.0;
     float invAmount = 1.0 - amount;
 
-    vOp = user_data.y & 0xffff;
+    vOp = user_data.y;
     vAmount = amount;
 
-    // This assignment is only used for component transfer filters but this
-    // assignment has to be done here and not in the component transfer case
-    // below because it doesn't get executed on Windows because of a suspected
-    // miscompile of this shader on Windows. See
-    // https://github.com/servo/webrender/wiki/Driver-issues#bug-1505871---assignment-to-varying-flat-arrays-inside-switch-statement-of-vertex-shader-suspected-miscompile-on-windows
-    vFuncs[0] = (user_data.y >> 28) & 0xf; // R
-    vFuncs[1] = (user_data.y >> 24) & 0xf; // G
-    vFuncs[2] = (user_data.y >> 20) & 0xf; // B
-    vFuncs[3] = (user_data.y >> 16) & 0xf; // A
-
     switch (vOp) {
         case 2: {
             // Grayscale
             vColorMat = mat3(
                 vec3(lumR + oneMinusLumR * invAmount, lumR - lumR * invAmount, lumR - lumR * invAmount),
                 vec3(lumG - lumG * invAmount, lumG + oneMinusLumG * invAmount, lumG - lumG * invAmount),
                 vec3(lumB - lumB * invAmount, lumB - lumB * invAmount, lumB + oneMinusLumB * invAmount)
             );
@@ -122,21 +104,16 @@ void brush_vs(
         case 10: {
             // Color Matrix
             vec4 mat_data[3] = fetch_from_gpu_cache_3(user_data.z);
             vec4 offset_data = fetch_from_gpu_cache_1(user_data.z + 4);
             vColorMat = mat3(mat_data[0].xyz, mat_data[1].xyz, mat_data[2].xyz);
             vColorOffset = offset_data.rgb;
             break;
         }
-        case 13: {
-            // Component Transfer
-            vTableAddress = user_data.z;
-            break;
-        }
         default: break;
     }
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 vec3 Contrast(vec3 Cs, float amount) {
     return Cs.rgb * amount - 0.5 * amount + 0.5;
@@ -195,68 +172,16 @@ Fragment brush_fs() {
             alpha *= vAmount;
             break;
         case 11:
             color = SrgbToLinear(color);
             break;
         case 12:
             color = LinearToSrgb(color);
             break;
-        case 13: // Component Transfer
-            int offset = 0;
-            vec4 texel;
-            int k;
-
-            // We push a different amount of data to the gpu cache depending
-            // on the function type.
-            // Identity => 0 blocks
-            // Table/Discrete => 64 blocks (256 values)
-            // Linear => 1 block (2 values)
-            // Gamma => 1 block (3 values)
-            // We loop through the color components and increment the offset
-            // (for the next color component) into the gpu cache based on how
-            // many blocks that function type put into the gpu cache.
-            // Table/Discrete use a 256 entry look up table.
-            // Linear/Gamma are a simple calculation.
-            vec4 colora = alpha != 0.0 ? Cs / alpha : Cs;
-            for (int i = 0; i < 4; i++) {
-                switch (vFuncs[i]) {
-                    case COMPONENT_TRANSFER_IDENTITY:
-                        break;
-                    case COMPONENT_TRANSFER_TABLE:
-                    case COMPONENT_TRANSFER_DISCRETE:
-                        // fetch value from lookup table
-                        k = int(floor(colora[i]*255.0));
-                        texel = fetch_from_gpu_cache_1(vTableAddress + offset + k/4);
-                        colora[i] = clamp(texel[k % 4], 0.0, 1.0);
-                        // offset plus 256/4 blocks
-                        offset = offset + 64;
-                        break;
-                    case COMPONENT_TRANSFER_LINEAR:
-                        // fetch the two values for use in the linear equation
-                        texel = fetch_from_gpu_cache_1(vTableAddress + offset);
-                        colora[i] = clamp(texel[0] * colora[i] + texel[1], 0.0, 1.0);
-                        // offset plus 1 block
-                        offset = offset + 1;
-                        break;
-                    case COMPONENT_TRANSFER_GAMMA:
-                        // fetch the three values for use in the gamma equation
-                        texel = fetch_from_gpu_cache_1(vTableAddress + offset);
-                        colora[i] = clamp(texel[0] * pow(colora[i], texel[1]) + texel[2], 0.0, 1.0);
-                        // offset plus 1 block
-                        offset = offset + 1;
-                        break;
-                    default:
-                        // shouldn't happen
-                        break;
-                }
-            }
-            color = colora.rgb;
-            alpha = colora.a;
-            break;
         default:
             color = vColorMat * color + vColorOffset;
     }
 
     // Fail-safe to ensure that we don't sample outside the rendered
     // portion of a blend source.
     alpha *= point_inside_rect(uv, vUvClipBounds.xy, vUvClipBounds.zw);
 
--- a/gfx/wr/webrender/res/gpu_cache.glsl
+++ b/gfx/wr/webrender/res/gpu_cache.glsl
@@ -28,25 +28,16 @@ vec4[2] fetch_from_gpu_cache_2_direct(iv
 vec4[2] fetch_from_gpu_cache_2(int address) {
     ivec2 uv = get_gpu_cache_uv(address);
     return vec4[2](
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(0, 0)),
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(1, 0))
     );
 }
 
-vec4 fetch_from_gpu_cache_1_direct(ivec2 address) {
-    return texelFetch(sGpuCache, address, 0);
-}
-
-vec4 fetch_from_gpu_cache_1(int address) {
-    ivec2 uv = get_gpu_cache_uv(address);
-    return texelFetch(sGpuCache, uv, 0);
-}
-
 #ifdef WR_VERTEX_SHADER
 
 vec4[8] fetch_from_gpu_cache_8(int address) {
     ivec2 uv = get_gpu_cache_uv(address);
     return vec4[8](
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(0, 0)),
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(1, 0)),
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(2, 0)),
@@ -89,16 +80,25 @@ vec4[4] fetch_from_gpu_cache_4(int addre
     return vec4[4](
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(0, 0)),
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(1, 0)),
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(2, 0)),
         TEXEL_FETCH(sGpuCache, uv, 0, ivec2(3, 0))
     );
 }
 
+vec4 fetch_from_gpu_cache_1_direct(ivec2 address) {
+    return texelFetch(sGpuCache, address, 0);
+}
+
+vec4 fetch_from_gpu_cache_1(int address) {
+    ivec2 uv = get_gpu_cache_uv(address);
+    return texelFetch(sGpuCache, uv, 0);
+}
+
 //TODO: image resource is too specific for this module
 
 struct ImageResource {
     RectWithEndpoint uv_rect;
     float layer;
     vec3 user_data;
 };
 
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -1383,17 +1383,16 @@ impl AlphaBatchBuilder {
                                             FilterOp::Saturate(..) => 5,
                                             FilterOp::Sepia(..) => 6,
                                             FilterOp::Brightness(..) => 7,
                                             FilterOp::Opacity(..) => 8,
                                             FilterOp::DropShadow(..) => 9,
                                             FilterOp::ColorMatrix(..) => 10,
                                             FilterOp::SrgbToLinear => 11,
                                             FilterOp::LinearToSrgb => 12,
-                                            FilterOp::ComponentTransfer => unreachable!(),
                                         };
 
                                         let user_data = match filter {
                                             FilterOp::Identity => 0x10000i32, // matches `Contrast(1)`
                                             FilterOp::Contrast(amount) |
                                             FilterOp::Grayscale(amount) |
                                             FilterOp::Invert(amount) |
                                             FilterOp::Saturate(amount) |
@@ -1409,17 +1408,16 @@ impl AlphaBatchBuilder {
                                             // Go through different paths
                                             FilterOp::Blur(..) |
                                             FilterOp::DropShadow(..) => {
                                                 unreachable!();
                                             }
                                             FilterOp::ColorMatrix(_) => {
                                                 picture.extra_gpu_data_handle.as_int(gpu_cache)
                                             }
-                                            FilterOp::ComponentTransfer => unreachable!(),
                                         };
 
                                         let (uv_rect_address, textures) = surface
                                             .resolve(
                                                 render_tasks,
                                                 ctx.resource_cache,
                                                 gpu_cache,
                                             );
@@ -1449,70 +1447,16 @@ impl AlphaBatchBuilder {
                                             key,
                                             bounding_rect,
                                             z_id,
                                             PrimitiveInstanceData::from(instance),
                                         );
                                     }
                                 }
                             }
-                            PictureCompositeMode::ComponentTransferFilter(handle) => {
-                                // This is basically the same as the general filter case above
-                                // except we store a little more data in the filter mode and
-                                // a gpu cache handle in the user data.
-                                let surface = ctx.surfaces[raster_config.surface_index.0]
-                                    .surface
-                                    .as_ref()
-                                    .expect("bug: surface must be allocated by now");
-
-
-                                let filter_data = &ctx.data_stores.filterdata[handle];
-                                let filter_mode : i32 = 13 |
-                                    ((filter_data.data.r_func.to_int() << 28 |
-                                      filter_data.data.g_func.to_int() << 24 |
-                                      filter_data.data.b_func.to_int() << 20 |
-                                      filter_data.data.a_func.to_int() << 16) as i32);
-
-                                let user_data = filter_data.gpu_cache_handle.as_int(gpu_cache);
-
-                                let (uv_rect_address, textures) = surface
-                                    .resolve(
-                                        render_tasks,
-                                        ctx.resource_cache,
-                                        gpu_cache,
-                                    );
-
-                                let key = BatchKey::new(
-                                    BatchKind::Brush(BrushBatchKind::Blend),
-                                    BlendMode::PremultipliedAlpha,
-                                    textures,
-                                );
-
-                                let prim_header_index = prim_headers.push(&prim_header, z_id, [
-                                    uv_rect_address.as_int(),
-                                    filter_mode,
-                                    user_data,
-                                ]);
-
-                                let instance = BrushInstance {
-                                    prim_header_index,
-                                    clip_task_address,
-                                    segment_index: INVALID_SEGMENT_INDEX,
-                                    edge_flags: EdgeAaSegmentMask::empty(),
-                                    brush_flags,
-                                    user_data: 0,
-                                };
-
-                                self.current_batch_list().push_single_instance(
-                                    key,
-                                    bounding_rect,
-                                    z_id,
-                                    PrimitiveInstanceData::from(instance),
-                                );
-                            }
                             PictureCompositeMode::Puppet { master: Some(source) } if ctx.is_picture_surface_visible(source) => return,
                             PictureCompositeMode::MixBlend { mode, backdrop } if ctx.is_picture_surface_visible(backdrop) => {
                                 let backdrop_picture = &ctx.prim_store.pictures[backdrop.0];
 
                                 let source_id = ctx
                                     .surfaces[raster_config.surface_index.0]
                                     .surface
                                     .as_ref()
--- a/gfx/wr/webrender/src/display_list_flattener.rs
+++ b/gfx/wr/webrender/src/display_list_flattener.rs
@@ -6,17 +6,17 @@ use api::{AlphaType, BorderDetails, Bord
 use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{DisplayItemRef, ExtendMode, ExternalScrollId, AuHelpers};
 use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop};
 use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, ColorDepth};
 use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
 use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId};
 use api::{PropertyBinding, ReferenceFrame, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity};
 use api::{Shadow, SpaceAndClipInfo, SpatialId, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
-use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData, TempFilterData};
+use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData};
 use app_units::Au;
 use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore};
 use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex};
 use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::FontInstance;
 use hit_test::{HitTestingItem, HitTestingRun};
 use image::simplify_repeated_primitive;
 use intern::{Handle, Internable, InternDebug};
@@ -38,17 +38,16 @@ use resource_cache::{FontInstanceMap, Im
 use scene::{Scene, StackingContextHelpers};
 use scene_builder::{InternerMut, Interners};
 use spatial_node::{StickyFrameInfo, ScrollFrameKind, SpatialNodeType};
 use std::{f32, mem, usize};
 use std::collections::vec_deque::VecDeque;
 use std::sync::Arc;
 use tiling::{CompositeOps};
 use util::{MaxRect, VecHelper};
-use ::filterdata::{SFilterDataComponent, SFilterData, SFilterDataKey};
 
 #[derive(Debug, Copy, Clone)]
 struct ClipNode {
     id: ClipChainId,
     count: usize,
 }
 
 impl ClipNode {
@@ -588,33 +587,31 @@ impl<'a> DisplayListFlattener<'a> {
     fn flatten_stacking_context(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         stacking_context: &StackingContext,
         spatial_node_index: SpatialNodeIndex,
         origin: LayoutPoint,
         filters: ItemRange<FilterOp>,
-        filter_datas: &[TempFilterData],
         reference_frame_relative_offset: &LayoutVector2D,
         is_backface_visible: bool,
         apply_pipeline_clip: bool,
     ) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
 
         let composition_operations = {
             // TODO(optimization?): self.traversal.display_list()
             let display_list = self.scene.get_display_list_for_pipeline(pipeline_id);
             CompositeOps::new(
                 stacking_context.filter_ops_for_compositing(display_list, filters),
-                stacking_context.filter_datas_for_compositing(display_list, filter_datas),
                 stacking_context.mix_blend_mode_for_compositing(),
             )
         };
 
         let clip_chain_id = match stacking_context.clip_id {
             Some(clip_id) => self.id_to_index_mapper.get_clip_chain_id(clip_id),
             None => ClipChainId::NONE,
         };
@@ -878,17 +875,16 @@ impl<'a> DisplayListFlattener<'a> {
                 let mut subtraversal = item.sub_iter();
                 self.flatten_stacking_context(
                     &mut subtraversal,
                     pipeline_id,
                     &info.stacking_context,
                     clip_and_scroll.spatial_node_index,
                     item.rect().origin,
                     item.filters(),
-                    item.filter_datas(),
                     &reference_frame_relative_offset,
                     prim_info.is_backface_visible,
                     apply_pipeline_clip,
                 );
                 return Some(subtraversal);
             }
             SpecificDisplayItem::PushReferenceFrame(ref info) => {
                 let mut subtraversal = item.sub_iter();
@@ -1005,18 +1001,16 @@ impl<'a> DisplayListFlattener<'a> {
                     info,
                     clip_and_scroll.spatial_node_index,
                     &reference_frame_relative_offset,
                 );
             }
 
             // Do nothing; these are dummy items for the display list parser
             SpecificDisplayItem::SetGradientStops => {}
-            SpecificDisplayItem::SetFilterOps => {}
-            SpecificDisplayItem::SetFilterData => {}
 
             SpecificDisplayItem::PopReferenceFrame |
             SpecificDisplayItem::PopStackingContext => {
                 unreachable!("Should have returned in parent method.")
             }
             SpecificDisplayItem::PushShadow(shadow) => {
                 self.push_shadow(shadow, clip_and_scroll);
             }
@@ -1422,17 +1416,17 @@ impl<'a> DisplayListFlattener<'a> {
             // TODO(gw): For now, as soon as this picture is in
             //           a 3D context, we draw it to an intermediate
             //           surface and apply plane splitting. However,
             //           there is a large optimization opportunity here.
             //           During culling, we can check if there is actually
             //           perspective present, and skip the plane splitting
             //           completely when that is not the case.
             Picture3DContext::In { ancestor_index, .. } => {
-                assert!(!leaf_composite_mode.is_none());
+                assert_ne!(leaf_composite_mode, None);
                 Picture3DContext::In { root_data: None, ancestor_index }
             }
             Picture3DContext::Out => Picture3DContext::Out,
         };
 
         let leaf_prim_list = PrimitiveList::new(
             stacking_context.primitives,
             &self.interners,
@@ -1508,51 +1502,19 @@ impl<'a> DisplayListFlattener<'a> {
                 stacking_context.is_backface_visible,
                 ClipChainId::NONE,
                 stacking_context.spatial_node_index,
                 &mut self.interners,
             );
         }
 
         // For each filter, create a new image with that composite mode.
-        let mut current_filter_data_index = 0;
         for filter in &stacking_context.composite_ops.filters {
             let filter = filter.sanitize();
-
-            let composite_mode = Some(match filter {
-                FilterOp::ComponentTransfer => {
-                    let filter_data =
-                        &stacking_context.composite_ops.filter_datas[current_filter_data_index];
-                    let filter_data = filter_data.sanitize();
-                    current_filter_data_index = current_filter_data_index + 1;
-                    if filter_data.is_identity() {
-                        continue
-                    } else {
-                        let filter_data_key = SFilterDataKey {
-                            data:
-                                SFilterData {
-                                    r_func: SFilterDataComponent::from_functype_values(
-                                        filter_data.func_r_type, &filter_data.r_values),
-                                    g_func: SFilterDataComponent::from_functype_values(
-                                        filter_data.func_g_type, &filter_data.g_values),
-                                    b_func: SFilterDataComponent::from_functype_values(
-                                        filter_data.func_b_type, &filter_data.b_values),
-                                    a_func: SFilterDataComponent::from_functype_values(
-                                        filter_data.func_a_type, &filter_data.a_values),
-                                },
-                        };
-
-                        let handle = self.interners
-                            .filterdata
-                            .intern(&filter_data_key, || ());
-                        PictureCompositeMode::ComponentTransferFilter(handle)
-                    }
-                }
-                _ => PictureCompositeMode::Filter(filter),
-            });
+            let composite_mode = Some(PictureCompositeMode::Filter(filter));
 
             let filter_pic_index = PictureIndex(self.prim_store.pictures
                 .alloc()
                 .init(PicturePrimitive::new_image(
                     composite_mode,
                     Picture3DContext::Out,
                     stacking_context.pipeline_id,
                     None,
deleted file mode 100644
--- a/gfx/wr/webrender/src/filterdata.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use std::{hash};
-use gpu_cache::{GpuCacheHandle};
-use frame_builder::FrameBuildingState;
-use gpu_cache::GpuDataRequest;
-use intern;
-use api::{ComponentTransferFuncType};
-
-
-pub use intern_types::filterdata::Handle as FilterDataHandle;
-
-#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
-#[cfg_attr(feature = "capture", derive(Serialize))]
-#[cfg_attr(feature = "replay", derive(Deserialize))]
-pub enum SFilterDataComponent {
-    Identity,
-    Table(Vec<f32>),
-    Discrete(Vec<f32>),
-    Linear(f32, f32),
-    Gamma(f32, f32, f32),
-}
-
-impl Eq for SFilterDataComponent {}
-
-impl hash::Hash for SFilterDataComponent {
-    fn hash<H: hash::Hasher>(&self, state: &mut H) {
-        match self {
-            SFilterDataComponent::Identity => {
-                0.hash(state);
-            }
-            SFilterDataComponent::Table(values) => {
-                1.hash(state);
-                values.len().hash(state);
-                for val in values {
-                    val.to_bits().hash(state);
-                }
-            }
-            SFilterDataComponent::Discrete(values) => {
-                2.hash(state);
-                values.len().hash(state);
-                for val in values {
-                    val.to_bits().hash(state);
-                }
-            }
-            SFilterDataComponent::Linear(a, b) => {
-                3.hash(state);
-                a.to_bits().hash(state);
-                b.to_bits().hash(state);
-            }
-            SFilterDataComponent::Gamma(a, b, c) => {
-                4.hash(state);
-                a.to_bits().hash(state);
-                b.to_bits().hash(state);
-                c.to_bits().hash(state);
-            }
-        }
-    }
-}
-
-impl SFilterDataComponent {
-    pub fn to_int(&self) -> u32 {
-        match self {
-            SFilterDataComponent::Identity => 0,
-            SFilterDataComponent::Table(_) => 1,
-            SFilterDataComponent::Discrete(_) => 2,
-            SFilterDataComponent::Linear(_, _) => 3,
-            SFilterDataComponent::Gamma(_, _, _) => 4,
-        }
-    }
-
-    pub fn from_functype_values(
-        func_type: ComponentTransferFuncType,
-        values: &[f32],
-    ) -> SFilterDataComponent {
-        match func_type {
-            ComponentTransferFuncType::Identity => SFilterDataComponent::Identity,
-            ComponentTransferFuncType::Table => SFilterDataComponent::Table(values.to_vec()),
-            ComponentTransferFuncType::Discrete => SFilterDataComponent::Discrete(values.to_vec()),
-            ComponentTransferFuncType::Linear => SFilterDataComponent::Linear(values[0], values[1]),
-            ComponentTransferFuncType::Gamma => SFilterDataComponent::Gamma(values[0], values[1], values[2]),
-        }
-    }
-}
-
-#[derive(Debug, Clone, MallocSizeOf, PartialEq, Eq, Hash)]
-#[cfg_attr(feature = "capture", derive(Serialize))]
-#[cfg_attr(feature = "replay", derive(Deserialize))]
-pub struct SFilterData {
-    pub r_func: SFilterDataComponent,
-    pub g_func: SFilterDataComponent,
-    pub b_func: SFilterDataComponent,
-    pub a_func: SFilterDataComponent,
-}
-
-#[derive(Debug, Clone, MallocSizeOf, PartialEq, Eq, Hash)]
-#[cfg_attr(feature = "capture", derive(Serialize))]
-#[cfg_attr(feature = "replay", derive(Deserialize))]
-pub struct SFilterDataKey {
-    pub data: SFilterData,
-}
-
-impl intern::InternDebug for SFilterDataKey {}
-
-#[derive(Debug)]
-#[cfg_attr(feature = "capture", derive(Serialize))]
-#[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(MallocSizeOf)]
-pub struct SFilterDataTemplate {
-    pub data: SFilterData,
-    pub gpu_cache_handle: GpuCacheHandle,
-}
-
-impl From<SFilterDataKey> for SFilterDataTemplate {
-    fn from(item: SFilterDataKey) -> Self {
-        SFilterDataTemplate {
-            data: item.data,
-            gpu_cache_handle: GpuCacheHandle::new(),
-        }
-    }
-}
-
-impl SFilterDataTemplate {
-    /// Update the GPU cache for a given filter data template. This may be called multiple
-    /// times per frame, by each primitive reference that refers to this interned
-    /// template. The initial request call to the GPU cache ensures that work is only
-    /// done if the cache entry is invalid (due to first use or eviction).
-    pub fn update(
-        &mut self,
-        frame_state: &mut FrameBuildingState,
-    ) {
-        if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) {
-            push_component_transfer_data(&self.data.r_func, &mut request);
-            push_component_transfer_data(&self.data.g_func, &mut request);
-            push_component_transfer_data(&self.data.b_func, &mut request);
-            push_component_transfer_data(&self.data.a_func, &mut request);
-            assert!(self.data.r_func != SFilterDataComponent::Identity
-                 || self.data.g_func != SFilterDataComponent::Identity
-                 || self.data.b_func != SFilterDataComponent::Identity
-                 || self.data.a_func != SFilterDataComponent::Identity);
-        }
-    }
-}
-
-fn push_component_transfer_data(
-    func_comp: &SFilterDataComponent,
-    request: &mut GpuDataRequest,
-) {
-    match func_comp {
-        SFilterDataComponent::Identity => { return; }
-        SFilterDataComponent::Table(values) |
-        SFilterDataComponent::Discrete(values) => {
-            // Push a 256 entry lookup table.
-            assert!(values.len() > 0);
-            for i in 0 .. 64 {
-                let mut arr = [0.0 ; 4];
-                for j in 0 .. 4 {
-                    if (values.len() == 1) || (i == 63 && j == 3) {
-                        arr[j] = values[values.len()-1];
-                    } else {
-                        let c = ((4*i + j) as f32)/255.0;
-                        match func_comp {
-                            SFilterDataComponent::Table(_) => {
-                                let n = (values.len()-1) as f32;
-                                let k = (n * c).floor() as u32;
-                                let ku = k as usize;
-                                assert!(ku < values.len()-1);
-                                arr[j] = values[ku] + (c*n - (k as f32)) * (values[ku+1] - values[ku]);
-                            }
-                            SFilterDataComponent::Discrete(_) => {
-                                let n = values.len() as f32;
-                                let k = (n * c).floor() as usize;
-                                assert!(k < values.len());
-                                arr[j] = values[k];
-                            }
-                            SFilterDataComponent::Identity |
-                            SFilterDataComponent::Linear(_,_) |
-                            SFilterDataComponent::Gamma(_,_,_) => {
-                                unreachable!();
-                            }
-                        }
-
-                    }
-                }
-
-                request.push(arr);
-            }
-        }
-        SFilterDataComponent::Linear(a, b) => {
-            request.push([*a, *b, 0.0, 0.0]);
-        }
-        SFilterDataComponent::Gamma(a, b, c) => {
-            request.push([*a, *b, *c, 0.0]);
-        }
-    }
-}
--- a/gfx/wr/webrender/src/intern_types.rs
+++ b/gfx/wr/webrender/src/intern_types.rs
@@ -98,17 +98,10 @@ pub type Interner = intern::Interner<Pic
 pub mod text_run {
 common!();
 use ::prim_store::text_run::{TextRunKey, TextRunTemplate};
 pub type Store = intern::DataStore<TextRunKey, TextRunTemplate, Marker>;
 pub type UpdateList = intern::UpdateList<TextRunKey>;
 pub type Interner = intern::Interner<TextRunKey, PrimitiveSceneData, Marker>;
 }
 
-pub mod filterdata {
-common!();
-use ::filterdata::{SFilterDataKey, SFilterDataTemplate};
-pub type Store = intern::DataStore<SFilterDataKey, SFilterDataTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<SFilterDataKey>;
-pub type Interner = intern::Interner<SFilterDataKey, (), Marker>;
-}
 
 
--- a/gfx/wr/webrender/src/lib.rs
+++ b/gfx/wr/webrender/src/lib.rs
@@ -85,17 +85,16 @@ mod clip_scroll_tree;
 mod debug_colors;
 mod debug_font_data;
 mod debug_render;
 #[cfg(feature = "debugger")]
 mod debug_server;
 mod device;
 mod display_list_flattener;
 mod ellipse;
-mod filterdata;
 mod frame_builder;
 mod freelist;
 #[cfg(any(target_os = "macos", target_os = "windows"))]
 mod gamma_lut;
 mod glyph_cache;
 mod glyph_rasterizer;
 mod gpu_cache;
 #[cfg(feature = "pathfinder")]
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -32,17 +32,16 @@ use resource_cache::ResourceCache;
 use scene::{FilterOpHelpers, SceneProperties};
 use scene_builder::Interners;
 use smallvec::SmallVec;
 use std::{mem, u16};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use texture_cache::TextureCacheHandle;
 use tiling::RenderTargetKind;
 use util::{ComparableVec, TransformedRectKind, MatrixHelpers, MaxRect};
-use ::filterdata::{FilterDataHandle};
 
 /*
  A picture represents a dynamically rendered image. It consists of:
 
  * A number of primitives that are drawn onto the picture.
  * A composite operation describing how to composite this
    picture into its parent.
  * A configuration describing how to draw the primitives on
@@ -1876,37 +1875,35 @@ bitflags! {
         /// Preserve-3D requires a surface for plane-splitting.
         const PRESERVE3D = 2;
     }
 }
 
 /// Specifies how this Picture should be composited
 /// onto the target it belongs to.
 #[allow(dead_code)]
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 pub enum PictureCompositeMode {
     /// Don't composite this picture in a standard way,
     /// can be used for pictures that need to be isolated but used
     /// manually, e.g. for the backdrop of mix-blend pictures.
     Puppet {
         /// The master picture that actually handles compositing
         /// of this one. If that picture turns out to be invisible,
         /// the puppet mode becomes a regular blit.
         master: Option<PictureIndex>,
     },
     /// Apply CSS mix-blend-mode effect.
     MixBlend {
         mode: MixBlendMode,
         backdrop: PictureIndex,
     },
-    /// Apply a CSS filter (except component transfer).
+    /// Apply a CSS filter.
     Filter(FilterOp),
-    /// Apply a component transfer filter.
-    ComponentTransferFilter(FilterDataHandle),
     /// Draw to intermediate surface, copy straight across. This
     /// is used for CSS isolation, and plane splitting.
     Blit(BlitReason),
     /// Used to cache a picture as a series of tiles.
     TileCache {
         clear_color: ColorF,
     },
 }
@@ -2862,17 +2859,16 @@ impl PicturePrimitive {
     pub fn prepare_for_render(
         &mut self,
         pic_index: PictureIndex,
         prim_instance: &PrimitiveInstance,
         clipped_prim_bounding_rect: WorldRect,
         surface_index: SurfaceIndex,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
-        data_stores: &mut DataStores,
     ) -> bool {
         let (mut pic_state_for_children, pic_context) = self.take_state_and_context();
 
         if let Some(ref mut splitter) = pic_state_for_children.plane_splitter {
             self.resolve_split_planes(splitter, frame_state);
         }
 
         let raster_config = match self.raster_config {
@@ -2885,16 +2881,17 @@ impl PicturePrimitive {
         let (raster_spatial_node_index, child_tasks, device_pixel_scale) = {
             let surface_info = &mut frame_state.surfaces[raster_config.surface_index.0];
             (
                 surface_info.raster_spatial_node_index,
                 surface_info.take_render_tasks(),
                 surface_info.device_pixel_scale,
             )
         };
+        let surfaces = &mut frame_state.surfaces;
 
         let (map_raster_to_world, map_pic_to_raster) = create_raster_mappers(
             prim_instance.spatial_node_index,
             raster_spatial_node_index,
             frame_context.screen_world_rect,
             frame_context.clip_scroll_tree,
         );
 
@@ -2918,24 +2915,24 @@ impl PicturePrimitive {
         //           probably worth tidying this code up to be a bit more consistent.
         //           Perhaps store the color matrix after the common data, even though
         //           it's not used by that shader.
 
         let surface = match raster_config.composite_mode {
             PictureCompositeMode::TileCache { .. } => {
                 // For a picture surface, just push any child tasks and tile
                 // blits up to the parent surface.
-                let surface = &mut frame_state.surfaces[surface_index.0];
+                let surface = &mut surfaces[surface_index.0];
                 surface.tasks.extend(child_tasks);
 
                 return true;
             }
             PictureCompositeMode::Filter(FilterOp::Blur(blur_radius)) => {
                 let blur_std_deviation = blur_radius * device_pixel_scale.0;
-                let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
+                let inflation_factor = surfaces[raster_config.surface_index.0].inflation_factor;
                 let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil() as i32;
 
                 // The clipped field is the part of the picture that is visible
                 // on screen. The unclipped field is the screen-space rect of
                 // the complete picture, if no screen / clip-chain was applied
                 // (this includes the extra space for blur region). To ensure
                 // that we draw a large enough part of the picture to get correct
                 // blur results, inflate that clipped area by the blur range, and
@@ -2979,17 +2976,17 @@ impl PicturePrimitive {
                     picture_task_id,
                     frame_state.render_tasks,
                     RenderTargetKind::Color,
                     ClearMode::Transparent,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(blur_render_task);
 
-                frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
+                surfaces[surface_index.0].tasks.push(render_task_id);
 
                 PictureSurface::RenderTask(render_task_id)
             }
             PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color)) => {
                 let blur_std_deviation = blur_radius * device_pixel_scale.0;
                 let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
                 let rounded_std_dev = blur_std_deviation.round();
                 // The clipped field is the part of the picture that is visible
@@ -3036,17 +3033,17 @@ impl PicturePrimitive {
                     frame_state.render_tasks,
                     RenderTargetKind::Color,
                     ClearMode::Transparent,
                 );
 
                 self.secondary_render_task_id = Some(picture_task_id);
 
                 let render_task_id = frame_state.render_tasks.add(blur_render_task);
-                frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
+                surfaces[surface_index.0].tasks.push(render_task_id);
 
                 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
                     // TODO(gw): This is very hacky code below! It stores an extra
                     //           brush primitive below for the special case of a
                     //           drop-shadow where we need a different local
                     //           rect for the shadow. To tidy this up in future,
                     //           we could consider abstracting the code in prim_store.rs
                     //           that writes a brush primitive header.
@@ -3097,44 +3094,17 @@ impl PicturePrimitive {
                     clipped.origin,
                     child_tasks,
                     uv_rect_kind,
                     pic_context.raster_spatial_node_index,
                     device_pixel_scale,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
-                frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
-                PictureSurface::RenderTask(render_task_id)
-            }
-            PictureCompositeMode::ComponentTransferFilter(handle) => {
-                let filter_data = &mut data_stores.filterdata[handle];
-                filter_data.update(frame_state);
-
-                let uv_rect_kind = calculate_uv_rect_kind(
-                    &pic_rect,
-                    &transform,
-                    &clipped,
-                    device_pixel_scale,
-                    true,
-                );
-
-                let picture_task = RenderTask::new_picture(
-                    RenderTaskLocation::Dynamic(None, clipped.size),
-                    unclipped.size,
-                    pic_index,
-                    clipped.origin,
-                    child_tasks,
-                    uv_rect_kind,
-                    pic_context.raster_spatial_node_index,
-                    device_pixel_scale,
-                );
-
-                let render_task_id = frame_state.render_tasks.add(picture_task);
-                frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
+                surfaces[surface_index.0].tasks.push(render_task_id);
                 PictureSurface::RenderTask(render_task_id)
             }
             PictureCompositeMode::Puppet { .. } |
             PictureCompositeMode::MixBlend { .. } |
             PictureCompositeMode::Blit(_) => {
                 // The SplitComposite shader used for 3d contexts doesn't snap
                 // to pixels, so we shouldn't snap our uv coordinates either.
                 let supports_snapping = match self.context_3d {
@@ -3157,22 +3127,22 @@ impl PicturePrimitive {
                     clipped.origin,
                     child_tasks,
                     uv_rect_kind,
                     pic_context.raster_spatial_node_index,
                     device_pixel_scale,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
-                frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
+                surfaces[surface_index.0].tasks.push(render_task_id);
                 PictureSurface::RenderTask(render_task_id)
             }
         };
 
-        frame_state.surfaces[raster_config.surface_index.0].surface = Some(surface);
+        surfaces[raster_config.surface_index.0].surface = Some(surface);
 
         true
     }
 }
 
 // Calculate a single homogeneous screen-space UV for a picture.
 fn calculate_screen_uv(
     local_pos: &PicturePoint,
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -2299,17 +2299,16 @@ impl PrimitiveStore {
                 let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
                 if pic.prepare_for_render(
                     pic_index,
                     prim_instance,
                     prim_info.clipped_world_rect,
                     pic_context.surface_index,
                     frame_context,
                     frame_state,
-                    data_stores,
                 ) {
                     if let Some(ref mut splitter) = pic_state.plane_splitter {
                         PicturePrimitive::add_split_plane(
                             splitter,
                             frame_state.transforms,
                             prim_instance,
                             pic.local_rect,
                             &prim_info.combined_local_clip_rect,
--- a/gfx/wr/webrender/src/prim_store/picture.rs
+++ b/gfx/wr/webrender/src/prim_store/picture.rs
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{
     ColorU, FilterOp, LayoutSize, LayoutPrimitiveInfo, MixBlendMode,
     PropertyBinding, PropertyBindingId, LayoutVector2D,
 };
-use intern::ItemUid;
 use app_units::Au;
 use display_list_flattener::{AsInstanceKind, IsVisible};
 use intern::{Internable, InternDebug};
 use intern_types;
 use picture::PictureCompositeMode;
 use prim_store::{
     PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData,
     PrimitiveInstanceKind, PrimitiveSceneData, PrimitiveStore, VectorKey,
@@ -36,17 +35,16 @@ pub enum PictureCompositeKey {
     Opacity(Au),
     OpacityBinding(PropertyBindingId, Au),
     Saturate(Au),
     Sepia(Au),
     DropShadow(VectorKey, Au, ColorU),
     ColorMatrix([Au; 20]),
     SrgbToLinear,
     LinearToSrgb,
-    ComponentTransfer(ItemUid),
 
     // MixBlendMode
     Multiply,
     Screen,
     Overlay,
     Darken,
     Lighten,
     ColorDodge,
@@ -112,22 +110,18 @@ impl From<Option<PictureCompositeMode>> 
                     }
                     FilterOp::ColorMatrix(values) => {
                         let mut quantized_values: [Au; 20] = [Au(0); 20];
                         for (value, result) in values.iter().zip(quantized_values.iter_mut()) {
                             *result = Au::from_f32_px(*value);
                         }
                         PictureCompositeKey::ColorMatrix(quantized_values)
                     }
-                    FilterOp::ComponentTransfer => unreachable!(),
                 }
             }
-            Some(PictureCompositeMode::ComponentTransferFilter(handle)) => {
-                PictureCompositeKey::ComponentTransfer(handle.uid())
-            }
             Some(PictureCompositeMode::Puppet { .. }) |
             Some(PictureCompositeMode::Blit(_)) |
             Some(PictureCompositeMode::TileCache { .. }) |
             None => {
                 PictureCompositeKey::Identity
             }
         }
     }
@@ -226,12 +220,12 @@ impl IsVisible for Picture {
 fn test_struct_sizes() {
     use std::mem;
     // The sizes of these structures are critical for performance on a number of
     // talos stress tests. If you get a failure here on CI, there's two possibilities:
     // (a) You made a structure smaller than it currently is. Great work! Update the
     //     test expectations and move on.
     // (b) You made a structure larger. This is not necessarily a problem, but should only
     //     be done with care, and after checking if talos performance regresses badly.
-    assert_eq!(mem::size_of::<Picture>(), 88, "Picture size changed");
+    assert_eq!(mem::size_of::<Picture>(), 84, "Picture size changed");
     assert_eq!(mem::size_of::<PictureTemplate>(), 20, "PictureTemplate size changed");
-    assert_eq!(mem::size_of::<PictureKey>(), 104, "PictureKey size changed");
+    assert_eq!(mem::size_of::<PictureKey>(), 96, "PictureKey size changed");
 }
--- a/gfx/wr/webrender/src/profiler.rs
+++ b/gfx/wr/webrender/src/profiler.rs
@@ -529,17 +529,16 @@ impl BackendProfileCounters {
                 line_decoration: ResourceProfileCounter::new("Interned line decorations"),
                 linear_grad: ResourceProfileCounter::new("Interned linear gradients"),
                 normal_border: ResourceProfileCounter::new("Interned normal borders"),
                 picture: ResourceProfileCounter::new("Interned pictures"),
                 radial_grad: ResourceProfileCounter::new("Interned radial gradients"),
                 text_run: ResourceProfileCounter::new("Interned text runs"),
                 yuv_image: ResourceProfileCounter::new("Interned YUV images"),
                 clip: ResourceProfileCounter::new("Interned clips"),
-                filterdata: ResourceProfileCounter::new("Interned filterdata"),
             },
         }
     }
 
     pub fn reset(&mut self) {
         self.total_time.reset();
         self.ipc.total_time.reset();
         self.ipc.build_time.reset();
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -1588,18 +1588,16 @@ impl ToDebugString for SpecificDisplayIt
             SpecificDisplayItem::Image(..) => String::from("image"),
             SpecificDisplayItem::Line(..) => String::from("line"),
             SpecificDisplayItem::PopAllShadows => String::from("pop_all_shadows"),
             SpecificDisplayItem::PopReferenceFrame => String::from("pop_reference_frame"),
             SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"),
             SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"),
             SpecificDisplayItem::PushReferenceFrame(..) => String::from("push_reference_frame"),
             SpecificDisplayItem::PushStackingContext(..) => String::from("push_stacking_context"),
-            SpecificDisplayItem::SetFilterOps => String::from("set_filter_ops"),
-            SpecificDisplayItem::SetFilterData => String::from("set_filter_data"),
             SpecificDisplayItem::RadialGradient(..) => String::from("radial_gradient"),
             SpecificDisplayItem::Rectangle(..) => String::from("rectangle"),
             SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
             SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
             SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
             SpecificDisplayItem::Text(..) => String::from("text"),
             SpecificDisplayItem::YuvImage(..) => String::from("yuv_image"),
             SpecificDisplayItem::PushCacheMarker(..) => String::from("push_cache_marker"),
--- a/gfx/wr/webrender/src/scene.rs
+++ b/gfx/wr/webrender/src/scene.rs
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayoutSize};
-use api::{FilterOp, TempFilterData, FilterData, ComponentTransferFuncType, LayoutTransform};
-use api::{PipelineId, PropertyBinding, PropertyBindingId, ItemRange, MixBlendMode, StackingContext};
+use api::{FilterOp, LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
+use api::{ItemRange, MixBlendMode, StackingContext};
 use internal_types::FastHashMap;
 use std::sync::Arc;
 
 /// Stores a map of the animated property bindings for the current display list. These
 /// can be used to animate the transform and/or opacity of a display list without
 /// re-submitting the display list itself.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -220,18 +220,17 @@ impl FilterOpHelpers for FilterOp {
             FilterOp::Grayscale(..) |
             FilterOp::HueRotate(..) |
             FilterOp::Invert(..) |
             FilterOp::Saturate(..) |
             FilterOp::Sepia(..) |
             FilterOp::DropShadow(..) |
             FilterOp::ColorMatrix(..) |
             FilterOp::SrgbToLinear |
-            FilterOp::LinearToSrgb |
-            FilterOp::ComponentTransfer  => true,
+            FilterOp::LinearToSrgb  => true,
             FilterOp::Opacity(_, amount) => {
                 amount > OPACITY_EPSILON
             }
         }
     }
 
     fn is_noop(&self) -> bool {
         match *self {
@@ -250,35 +249,28 @@ impl FilterOpHelpers for FilterOp {
             },
             FilterOp::ColorMatrix(matrix) => {
                 matrix == [1.0, 0.0, 0.0, 0.0,
                            0.0, 1.0, 0.0, 0.0,
                            0.0, 0.0, 1.0, 0.0,
                            0.0, 0.0, 0.0, 1.0,
                            0.0, 0.0, 0.0, 0.0]
             }
-            FilterOp::SrgbToLinear |
-            FilterOp::LinearToSrgb |
-            FilterOp::ComponentTransfer => false,
+            FilterOp::SrgbToLinear | FilterOp::LinearToSrgb => false,
         }
     }
 }
 
 pub trait StackingContextHelpers {
     fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
     fn filter_ops_for_compositing(
         &self,
         display_list: &BuiltDisplayList,
         input_filters: ItemRange<FilterOp>,
     ) -> Vec<FilterOp>;
-    fn filter_datas_for_compositing(
-        &self,
-        display_list: &BuiltDisplayList,
-        input_filter_datas: &[TempFilterData],
-    ) -> Vec<FilterData>;
 }
 
 impl StackingContextHelpers for StackingContext {
     fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
         match self.mix_blend_mode {
             MixBlendMode::Normal => None,
             _ => Some(self.mix_blend_mode),
         }
@@ -293,35 +285,9 @@ impl StackingContextHelpers for Stacking
         //           we could probably make it a bit
         //           more efficient than cloning these here.
         let mut filters = vec![];
         for filter in display_list.get(input_filters) {
             filters.push(filter);
         }
         filters
     }
-
-    fn filter_datas_for_compositing(
-        &self,
-        display_list: &BuiltDisplayList,
-        input_filter_datas: &[TempFilterData],
-    ) -> Vec<FilterData> {
-        // TODO(gw): Now that we resolve these later on,
-        //           we could probably make it a bit
-        //           more efficient than cloning these here.
-        let mut filter_datas = vec![];
-        for temp_filter_data in input_filter_datas {
-            let func_types : Vec<ComponentTransferFuncType> = display_list.get(temp_filter_data.func_types).collect();
-            debug_assert!(func_types.len() == 4);
-            filter_datas.push( FilterData {
-                func_r_type: func_types[0],
-                r_values: display_list.get(temp_filter_data.r_values).collect(),
-                func_g_type: func_types[1],
-                g_values: display_list.get(temp_filter_data.g_values).collect(),
-                func_b_type: func_types[2],
-                b_values: display_list.get(temp_filter_data.b_values).collect(),
-                func_a_type: func_types[3],
-                a_values: display_list.get(temp_filter_data.a_values).collect(),
-            });
-        }
-        filter_datas
-    }
 }
--- a/gfx/wr/webrender/src/tiling.rs
+++ b/gfx/wr/webrender/src/tiling.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{ColorF, BorderStyle, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
-use api::{DocumentLayer, FilterOp, FilterData, ImageFormat, DevicePoint};
+use api::{DocumentLayer, FilterOp, ImageFormat, DevicePoint};
 use api::{MixBlendMode, PipelineId, DeviceRect, LayoutSize, WorldRect};
 use batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image};
 use clip::ClipStore;
 use clip_scroll_tree::{ClipScrollTree};
 use debug_render::DebugItem;
 use device::{Texture};
 #[cfg(feature = "pathfinder")]
 use euclid::{TypedPoint2D, TypedVector2D};
@@ -1100,35 +1100,31 @@ impl RenderPass {
         }
     }
 }
 
 #[derive(Debug, Clone, Default)]
 pub struct CompositeOps {
     // Requires only a single texture as input (e.g. most filters)
     pub filters: Vec<FilterOp>,
-    pub filter_datas: Vec<FilterData>,
 
     // Requires two source textures (e.g. mix-blend-mode)
     pub mix_blend_mode: Option<MixBlendMode>,
 }
 
 impl CompositeOps {
-    pub fn new(filters: Vec<FilterOp>,
-               filter_datas: Vec<FilterData>,
-               mix_blend_mode: Option<MixBlendMode>) -> Self {
+    pub fn new(filters: Vec<FilterOp>, mix_blend_mode: Option<MixBlendMode>) -> Self {
         CompositeOps {
             filters,
-            filter_datas,
             mix_blend_mode,
         }
     }
 
     pub fn is_empty(&self) -> bool {
-        self.filters.is_empty() && self.filter_datas.is_empty() && self.mix_blend_mode.is_none()
+        self.filters.is_empty() && self.mix_blend_mode.is_none()
     }
 }
 
 /// A rendering-oriented representation of the frame built by the render backend
 /// and presented to the renderer.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct Frame {
--- a/gfx/wr/webrender_api/src/api.rs
+++ b/gfx/wr/webrender_api/src/api.rs
@@ -832,17 +832,16 @@ macro_rules! enumerate_interners {
             image_border,
             image,
             yuv_image,
             line_decoration,
             linear_grad,
             radial_grad,
             picture,
             text_run,
-            filterdata,
         }
     }
 }
 
 macro_rules! declare_interning_memory_report {
     ( $( $name: ident, )+ ) => {
         #[repr(C)]
         #[derive(AddAssign, Clone, Debug, Default, Deserialize, Serialize)]
--- a/gfx/wr/webrender_api/src/display_item.rs
+++ b/gfx/wr/webrender_api/src/display_item.rs
@@ -122,18 +122,16 @@ pub enum SpecificDisplayItem {
     PopReferenceFrame,
     PushStackingContext(PushStackingContextDisplayItem),
     PopStackingContext,
     SetGradientStops,
     PushShadow(Shadow),
     PopAllShadows,
     PushCacheMarker(CacheMarkerDisplayItem),
     PopCacheMarker,
-    SetFilterOps,
-    SetFilterData,
 }
 
 /// This is a "complete" version of the DI specifics,
 /// containing the auxiliary data within the corresponding
 /// enumeration variants, to be used for debug serialization.
 #[cfg(any(feature = "serialize", feature = "deserialize"))]
 #[cfg_attr(feature = "serialize", derive(Serialize))]
 #[cfg_attr(feature = "deserialize", derive(Deserialize))]
@@ -150,25 +148,23 @@ pub enum CompletelySpecificDisplayItem {
     YuvImage(YuvImageDisplayItem),
     Border(BorderDisplayItem),
     BoxShadow(BoxShadowDisplayItem),
     Gradient(GradientDisplayItem),
     RadialGradient(RadialGradientDisplayItem),
     Iframe(IframeDisplayItem),
     PushReferenceFrame(ReferenceFrameDisplayListItem),
     PopReferenceFrame,
-    PushStackingContext(PushStackingContextDisplayItem),
+    PushStackingContext(PushStackingContextDisplayItem, Vec<FilterOp>),
     PopStackingContext,
     SetGradientStops(Vec<GradientStop>),
     PushShadow(Shadow),
     PopAllShadows,
     PushCacheMarker(CacheMarkerDisplayItem),
     PopCacheMarker,
-    SetFilterOps(Vec<FilterOp>),
-    SetFilterData(FilterData),
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ClipDisplayItem {
     pub id: ClipId,
     pub image_mask: Option<ImageMask>,
 }
 
@@ -561,17 +557,18 @@ pub struct PushStackingContextDisplayIte
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct StackingContext {
     pub transform_style: TransformStyle,
     pub mix_blend_mode: MixBlendMode,
     pub clip_id: Option<ClipId>,
     pub raster_space: RasterSpace,
     /// True if picture caching should be used on this stacking context.
     pub cache_tiles: bool,
-} // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>
+} // IMPLICIT: filters: Vec<FilterOp>
+
 
 #[repr(u32)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub enum TransformStyle {
     Flat = 0,
     Preserve3D = 1,
 }
 
@@ -639,17 +636,16 @@ pub enum FilterOp {
     Invert(f32),
     Opacity(PropertyBinding<f32>, f32),
     Saturate(f32),
     Sepia(f32),
     DropShadow(LayoutVector2D, f32, ColorF),
     ColorMatrix([f32; 20]),
     SrgbToLinear,
     LinearToSrgb,
-    ComponentTransfer,
 }
 
 impl FilterOp {
     /// Ensure that the parameters for a filter operation
     /// are sensible.
     pub fn sanitize(self) -> FilterOp {
         match self {
             FilterOp::Blur(radius) => {
@@ -660,113 +656,16 @@ impl FilterOp {
                 let radius = radius.min(MAX_BLUR_RADIUS);
                 FilterOp::DropShadow(offset, radius, color)
             }
             filter => filter,
         }
     }
 }
 
-#[repr(u8)]
-#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
-pub enum ComponentTransferFuncType {
-  Identity = 0,
-  Table = 1,
-  Discrete = 2,
-  Linear = 3,
-  Gamma = 4,
-}
-
-#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
-pub struct FilterData {
-    pub func_r_type: ComponentTransferFuncType,
-    pub r_values: Vec<f32>,
-    pub func_g_type: ComponentTransferFuncType,
-    pub g_values: Vec<f32>,
-    pub func_b_type: ComponentTransferFuncType,
-    pub b_values: Vec<f32>,
-    pub func_a_type: ComponentTransferFuncType,
-    pub a_values: Vec<f32>,
-}
-
-fn sanitize_func_type(
-    func_type: ComponentTransferFuncType,
-    values: &[f32],
-) -> ComponentTransferFuncType {
-    if values.is_empty() {
-        return ComponentTransferFuncType::Identity;
-    }
-    if values.len() < 2 && func_type == ComponentTransferFuncType::Linear {
-        return ComponentTransferFuncType::Identity;
-    }
-    if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma {
-        return ComponentTransferFuncType::Identity;
-    }
-    func_type
-}
-
-fn sanitize_values(
-    func_type: ComponentTransferFuncType,
-    values: &[f32],
-) -> bool {
-    if values.len() < 2 && func_type == ComponentTransferFuncType::Linear {
-        return false;
-    }
-    if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma {
-        return false;
-    }
-    true
-}
-
-impl FilterData {
-    /// Ensure that the number of values matches up with the function type.
-    pub fn sanitize(&self) -> FilterData {
-        FilterData {
-            func_r_type: sanitize_func_type(self.func_r_type, &self.r_values),
-            r_values:
-                    if sanitize_values(self.func_r_type, &self.r_values) {
-                        self.r_values.clone()
-                    } else {
-                        Vec::new()
-                    },
-            func_g_type: sanitize_func_type(self.func_g_type, &self.g_values),
-            g_values:
-                    if sanitize_values(self.func_g_type, &self.g_values) {
-                        self.g_values.clone()
-                    } else {
-                        Vec::new()
-                    },
-
-            func_b_type: sanitize_func_type(self.func_b_type, &self.b_values),
-            b_values:
-                    if sanitize_values(self.func_b_type, &self.b_values) {
-                        self.b_values.clone()
-                    } else {
-                        Vec::new()
-                    },
-
-            func_a_type: sanitize_func_type(self.func_a_type, &self.a_values),
-            a_values:
-                    if sanitize_values(self.func_a_type, &self.a_values) {
-                        self.a_values.clone()
-                    } else {
-                        Vec::new()
-                    },
-
-        }
-    }
-
-    pub fn is_identity(&self) -> bool {
-        self.func_r_type == ComponentTransferFuncType::Identity &&
-        self.func_g_type == ComponentTransferFuncType::Identity &&
-        self.func_b_type == ComponentTransferFuncType::Identity &&
-        self.func_a_type == ComponentTransferFuncType::Identity
-    }
-}
-
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct IframeDisplayItem {
     pub pipeline_id: PipelineId,
     pub ignore_missing_pipeline: bool,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ImageDisplayItem {
--- a/gfx/wr/webrender_api/src/display_list.rs
+++ b/gfx/wr/webrender_api/src/display_list.rs
@@ -56,24 +56,16 @@ impl<T> Default for ItemRange<T> {
 
 impl<T> ItemRange<T> {
     pub fn is_empty(&self) -> bool {
         // Nothing more than space for a length (0).
         self.length <= mem::size_of::<u64>()
     }
 }
 
-pub struct TempFilterData {
-    pub func_types: ItemRange<di::ComponentTransferFuncType>,
-    pub r_values: ItemRange<f32>,
-    pub g_values: ItemRange<f32>,
-    pub b_values: ItemRange<f32>,
-    pub a_values: ItemRange<f32>,
-}
-
 /// A display list.
 #[derive(Clone, Default)]
 pub struct BuiltDisplayList {
     /// Serde encoded bytes. Mostly DisplayItems, but some mixed in slices.
     data: Vec<u8>,
     descriptor: BuiltDisplayListDescriptor,
 }
 
@@ -98,17 +90,16 @@ pub struct BuiltDisplayListDescriptor {
 
 pub struct BuiltDisplayListIter<'a> {
     list: &'a BuiltDisplayList,
     data: &'a [u8],
     cur_item: di::DisplayItem,
     cur_stops: ItemRange<di::GradientStop>,
     cur_glyphs: ItemRange<GlyphInstance>,
     cur_filters: ItemRange<di::FilterOp>,
-    cur_filter_data: Vec<TempFilterData>,
     cur_clip_chain_items: ItemRange<di::ClipId>,
     cur_complex_clip: (ItemRange<di::ComplexClipRegion>, usize),
     peeking: Peek,
 }
 
 pub struct DisplayItemRef<'a: 'b, 'b> {
     iter: &'b BuiltDisplayListIter<'a>,
 }
@@ -219,17 +210,16 @@ impl<'a> BuiltDisplayListIter<'a> {
                 // Dummy data, will be overwritten by `next`
                 item: di::SpecificDisplayItem::PopStackingContext,
                 layout: di::LayoutPrimitiveInfo::new(LayoutRect::zero()),
                 space_and_clip: di::SpaceAndClipInfo::root_scroll(PipelineId::dummy())
             },
             cur_stops: ItemRange::default(),
             cur_glyphs: ItemRange::default(),
             cur_filters: ItemRange::default(),
-            cur_filter_data: Vec::new(),
             cur_clip_chain_items: ItemRange::default(),
             cur_complex_clip: (ItemRange::default(), 0),
             peeking: Peek::NotPeeking,
         }
     }
 
     pub fn display_list(&self) -> &'a BuiltDisplayList {
         self.list
@@ -255,25 +245,16 @@ impl<'a> BuiltDisplayListIter<'a> {
         self.cur_clip_chain_items = ItemRange::default();
 
         loop {
             self.next_raw()?;
             if let SetGradientStops = self.cur_item.item {
                 // SetGradientStops is a dummy item that most consumers should ignore
                 continue;
             }
-            if let SetFilterOps = self.cur_item.item {
-                // SetFilterOps is a dummy item that most consumers should ignore
-                continue;
-            }
-            if let SetFilterData = self.cur_item.item {
-                // SetFilterData is a dummy item that most consumers should ignore
-                continue;
-            }
-
             break;
         }
 
         Some(self.as_ref())
     }
 
     /// Gets the next display item, even if it's a dummy. Also doesn't handle peeking
     /// and may leave irrelevant ranges live (so a Clip may have GradientStops if
@@ -290,35 +271,24 @@ impl<'a> BuiltDisplayListIter<'a> {
             bincode::deserialize_in_place(reader, &mut self.cur_item)
                 .expect("MEH: malicious process?");
         }
 
         match self.cur_item.item {
             SetGradientStops => {
                 self.cur_stops = skip_slice::<di::GradientStop>(self.list, &mut self.data).0;
             }
-            SetFilterOps => {
-                self.cur_filters = skip_slice::<di::FilterOp>(self.list, &mut self.data).0;
-            }
-            SetFilterData => {
-                self.cur_filter_data.push(TempFilterData {
-                    func_types: skip_slice::<di::ComponentTransferFuncType>(self.list, &mut self.data).0,
-                    r_values: skip_slice::<f32>(self.list, &mut self.data).0,
-                    g_values: skip_slice::<f32>(self.list, &mut self.data).0,
-                    b_values: skip_slice::<f32>(self.list, &mut self.data).0,
-                    a_values: skip_slice::<f32>(self.list, &mut self.data).0,
-                });
-            }
             ClipChain(_) => {
                 self.cur_clip_chain_items = skip_slice::<di::ClipId>(self.list, &mut self.data).0;
             }
             Clip(_) | ScrollFrame(_) => {
                 self.cur_complex_clip = self.skip_slice::<di::ComplexClipRegion>()
             }
             Text(_) => self.cur_glyphs = self.skip_slice::<GlyphInstance>().0,
+            PushStackingContext(_) => self.cur_filters = self.skip_slice::<di::FilterOp>().0,
             _ => { /* do nothing */ }
         }
 
         Some(self.as_ref())
     }
 
     fn skip_slice<T: for<'de> Deserialize<'de>>(&mut self) -> (ItemRange<T>, usize) {
         skip_slice::<T>(self.list, &mut self.data)
@@ -414,20 +384,16 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
     pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
         self.iter.cur_glyphs
     }
 
     pub fn filters(&self) -> ItemRange<di::FilterOp> {
         self.iter.cur_filters
     }
 
-    pub fn filter_datas(&self) -> &Vec<TempFilterData> {
-        &self.iter.cur_filter_data
-    }
-
     pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> {
         self.iter.cur_clip_chain_items
     }
 
     pub fn display_list(&self) -> &BuiltDisplayList {
         self.iter.display_list()
     }
 
@@ -516,39 +482,21 @@ impl Serialize for BuiltDisplayList {
                     di::SpecificDisplayItem::YuvImage(v) => YuvImage(v),
                     di::SpecificDisplayItem::Border(v) => Border(v),
                     di::SpecificDisplayItem::BoxShadow(v) => BoxShadow(v),
                     di::SpecificDisplayItem::Gradient(v) => Gradient(v),
                     di::SpecificDisplayItem::RadialGradient(v) => RadialGradient(v),
                     di::SpecificDisplayItem::Iframe(v) => Iframe(v),
                     di::SpecificDisplayItem::PushReferenceFrame(v) => PushReferenceFrame(v),
                     di::SpecificDisplayItem::PopReferenceFrame => PopReferenceFrame,
-                    di::SpecificDisplayItem::PushStackingContext(v) => PushStackingContext(v),
-                    di::SpecificDisplayItem::PopStackingContext => PopStackingContext,
-                    di::SpecificDisplayItem::SetFilterOps => SetFilterOps(
+                    di::SpecificDisplayItem::PushStackingContext(v) => PushStackingContext(
+                        v,
                         item.iter.list.get(item.iter.cur_filters).collect()
                     ),
-                    di::SpecificDisplayItem::SetFilterData => {
-                        debug_assert!(!item.iter.cur_filter_data.is_empty());
-                        let temp_filter_data = &item.iter.cur_filter_data[item.iter.cur_filter_data.len()-1];
-
-                        let func_types: Vec<di::ComponentTransferFuncType> =
-                            item.iter.list.get(temp_filter_data.func_types).collect();
-                        debug_assert!(func_types.len() == 4);
-                        SetFilterData(di::FilterData {
-                            func_r_type: func_types[0],
-                            r_values: item.iter.list.get(temp_filter_data.r_values).collect(),
-                            func_g_type: func_types[1],
-                            g_values: item.iter.list.get(temp_filter_data.g_values).collect(),
-                            func_b_type: func_types[2],
-                            b_values: item.iter.list.get(temp_filter_data.b_values).collect(),
-                            func_a_type: func_types[3],
-                            a_values: item.iter.list.get(temp_filter_data.a_values).collect(),
-                        })
-                    },
+                    di::SpecificDisplayItem::PopStackingContext => PopStackingContext,
                     di::SpecificDisplayItem::SetGradientStops => SetGradientStops(
                         item.iter.list.get(item.iter.cur_stops).collect()
                     ),
                     di::SpecificDisplayItem::PushShadow(v) => PushShadow(v),
                     di::SpecificDisplayItem::PopAllShadows => PopAllShadows,
                     di::SpecificDisplayItem::PushCacheMarker(m) => PushCacheMarker(m),
                     di::SpecificDisplayItem::PopCacheMarker => PopCacheMarker,
                 },
@@ -621,35 +569,19 @@ impl<'de> Deserialize<'de> for BuiltDisp
                         total_clip_nodes += 1;
                         di::SpecificDisplayItem::Iframe(specific_item)
                     }
                     PushReferenceFrame(v) => {
                         total_spatial_nodes += 1;
                         di::SpecificDisplayItem::PushReferenceFrame(v)
                     }
                     PopReferenceFrame => di::SpecificDisplayItem::PopReferenceFrame,
-                    PushStackingContext(specific_item) => {
-                        di::SpecificDisplayItem::PushStackingContext(specific_item)
-                    },
-                    SetFilterOps(filters) => {
+                    PushStackingContext(specific_item, filters) => {
                         DisplayListBuilder::push_iter_impl(&mut temp, filters);
-                        di::SpecificDisplayItem::SetFilterOps
-                    },
-                    SetFilterData(filter_data) => {
-                        let func_types: Vec<di::ComponentTransferFuncType> =
-                            [filter_data.func_r_type,
-                             filter_data.func_g_type,
-                             filter_data.func_b_type,
-                             filter_data.func_a_type].to_vec();
-                        DisplayListBuilder::push_iter_impl(&mut temp, func_types);
-                        DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values);
-                        DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values);
-                        DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values);
-                        DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values);
-                        di::SpecificDisplayItem::SetFilterData
+                        di::SpecificDisplayItem::PushStackingContext(specific_item)
                     },
                     PopStackingContext => di::SpecificDisplayItem::PopStackingContext,
                     SetGradientStops(stops) => {
                         DisplayListBuilder::push_iter_impl(&mut temp, stops);
                         di::SpecificDisplayItem::SetGradientStops
                     },
                     PushShadow(specific_item) => di::SpecificDisplayItem::PushShadow(specific_item),
                     PopAllShadows => di::SpecificDisplayItem::PopAllShadows,
@@ -1362,76 +1294,59 @@ impl DisplayListBuilder {
     pub fn push_stacking_context(
         &mut self,
         layout: &di::LayoutPrimitiveInfo,
         spatial_id: di::SpatialId,
         clip_id: Option<di::ClipId>,
         transform_style: di::TransformStyle,
         mix_blend_mode: di::MixBlendMode,
         filters: &[di::FilterOp],
-        filter_datas: &[di::FilterData],
         raster_space: di::RasterSpace,
         cache_tiles: bool,
     ) {
-        self.push_new_empty_item(&di::SpecificDisplayItem::SetFilterOps);
-        self.push_iter(filters);
-
-        for filter_data in filter_datas {
-            let func_types = [
-                filter_data.func_r_type, filter_data.func_g_type,
-                filter_data.func_b_type, filter_data.func_a_type];
-            self.push_new_empty_item(&di::SpecificDisplayItem::SetFilterData);
-            self.push_iter(&func_types);
-            self.push_iter(&filter_data.r_values);
-            self.push_iter(&filter_data.g_values);
-            self.push_iter(&filter_data.b_values);
-            self.push_iter(&filter_data.a_values);
-        }
-
         let item = di::SpecificDisplayItem::PushStackingContext(di::PushStackingContextDisplayItem {
             stacking_context: di::StackingContext {
                 transform_style,
                 mix_blend_mode,
                 clip_id,
                 raster_space,
                 cache_tiles,
             },
         });
 
         self.push_item(&item, layout, &di::SpaceAndClipInfo {
             spatial_id,
             clip_id: di::ClipId::invalid(),
         });
+        self.push_iter(filters);
     }
 
     /// Helper for examples/ code.
     pub fn push_simple_stacking_context(
         &mut self,
         layout: &di::LayoutPrimitiveInfo,
         spatial_id: di::SpatialId,
     ) {
-        self.push_simple_stacking_context_with_filters(layout, spatial_id, &[], &[]);
+        self.push_simple_stacking_context_with_filters(layout, spatial_id, &[]);
     }
 
     /// Helper for examples/ code.
     pub fn push_simple_stacking_context_with_filters(
         &mut self,
         layout: &di::LayoutPrimitiveInfo,
         spatial_id: di::SpatialId,
         filters: &[di::FilterOp],
-        filter_datas: &[di::FilterData],
     ) {
         self.push_stacking_context(
             layout,
             spatial_id,
             None,
             di::TransformStyle::Flat,
             di::MixBlendMode::Normal,
             filters,
-            filter_datas,
             di::RasterSpace::Screen,
             /* cache_tiles = */ false,
         );
     }
 
     pub fn pop_stacking_context(&mut self) {
         self.push_new_empty_item(&di::SpecificDisplayItem::PopStackingContext);
     }
deleted file mode 100644
--- a/gfx/wr/wrench/reftests/filters/filter-component-transfer-ref.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
----
-root:
-  items:
-    - type: stacking-context
-      bounds: [0, 0, 50, 250]
-      items:
-        - type: rect
-          bounds: [0, 0, 50, 50]
-          color: [255, 0, 255, 1]
-        - type: rect
-          bounds: [0, 50, 50, 50]
-          color: [0, 255, 141, 1]
-        - type: rect
-          bounds: [0, 100, 50, 50]
-          color: [255, 255, 0, 1]
-        - type: rect
-          bounds: [0, 150, 50, 50]
-          color: [191, 128, 128, 1]
-        - type: rect
-          bounds: [0, 200, 50, 50]
-          color: [0, 255, 24, 1]
deleted file mode 100644
--- a/gfx/wr/wrench/reftests/filters/filter-component-transfer.yaml
+++ /dev/null
@@ -1,118 +0,0 @@
----
-root:
-  items:
-    - type: stacking-context
-      bounds: [0, 0, 50, 250]
-      items:
-        - type: stacking-context
-          bounds: [0, 0, 50, 50]
-          filters:
-            - component-transfer
-          filter-datas:
-            - - - Identity
-                - Identity
-                - Identity
-                - Identity
-              - []
-              - []
-              - []
-              - []
-          items:
-            - type: rect
-              bounds: [0, 0, 50, 50]
-              color: [255, 0, 255, 1]
-        - type: stacking-context
-          bounds: [0, 50, 50, 50]
-          filters:
-            - component-transfer
-          filter-datas:
-            - - - Table
-                - Table
-                - Table
-                - Identity
-              - - "1"
-                - "1"
-                - "0"
-                - "0"
-              - - "0"
-                - "0"
-                - "1"
-                - "1"
-              - - "0"
-                - "1"
-                - "1"
-                - "0"
-              - []
-          items:
-            - type: rect
-              bounds: [0, 0, 50, 50]
-              color: [173, 255, 47, 1]
-        - type: stacking-context
-          bounds: [0, 100, 50, 50]
-          filters:
-            - component-transfer
-          filter-datas:
-            - - - Discrete
-                - Discrete
-                - Discrete
-                - Identity
-              - - "1"
-                - "1"
-                - "0"
-                - "0"
-              - - "0"
-                - "0"
-                - "1"
-                - "1"
-              - - "0"
-                - "1"
-                - "1"
-                - "0"
-              - []
-          items:
-            - type: rect
-              bounds: [0, 0, 50, 50]
-              color: [0, 255, 255, 1]
-        - type: stacking-context
-          bounds: [0, 150, 50, 50]
-          filters:
-            - component-transfer
-          filter-datas:
-            - - - Linear
-                - Linear
-                - Linear
-                - Identity
-              - - "0.5"
-                - "0.25"
-              - - "0.5"
-                - "0"
-              - - "0.5"
-                - "0.5"
-              - []
-          items:
-            - type: rect
-              bounds: [0, 0, 50, 50]
-              color: [255, 255, 0, 1]
-        - type: stacking-context
-          bounds: [0, 200, 50, 50]
-          filters:
-            - component-transfer
-          filter-datas:
-            - - - Gamma
-                - Gamma
-                - Gamma
-                - Identity
-              - - "2"
-                - "5"
-                - "-1"
-              - - "2"
-                - "3"
-                - "0"
-              - - "2"
-                - "1"
-                - "-1.75"
-              - []
-          items:
-            - type: rect
-              bounds: [0, 0, 50, 50]
-              color: [135, 206, 235, 1]
--- a/gfx/wr/wrench/reftests/filters/reftest.list
+++ b/gfx/wr/wrench/reftests/filters/reftest.list
@@ -4,17 +4,16 @@ platform(linux,mac) == draw_calls(6) col
 == invisible.yaml invisible-ref.yaml
 color_targets(1) alpha_targets(0) == opacity.yaml opacity-ref.yaml
 color_targets(1) alpha_targets(0) == opacity-combined.yaml opacity-combined-ref.yaml
 == opacity-overlap.yaml opacity-overlap-ref.yaml
 == filter-brightness.yaml filter-brightness-ref.yaml
 == filter-brightness-2.yaml filter-brightness-2-ref.yaml
 == filter-brightness-3.yaml filter-brightness-3-ref.yaml
 == filter-brightness-4.yaml filter-brightness-4-ref.yaml
-== filter-component-transfer.yaml filter-component-transfer-ref.yaml
 == filter-color-matrix.yaml filter-color-matrix-ref.yaml
 == filter-contrast-gray-alpha-1.yaml filter-contrast-gray-alpha-1-ref.yaml
 == filter-invert.yaml filter-invert-ref.yaml
 == filter-invert-2.yaml filter-invert-2-ref.yaml
 platform(linux,mac) fuzzy(1,133) == filter-large-blur-radius.yaml filter-large-blur-radius.png
 == draw_calls(4) color_targets(4) alpha_targets(0) filter-small-blur-radius.yaml filter-small-blur-radius.png
 == filter-saturate-red-1.yaml filter-saturate-red-1-ref.yaml
 == filter-saturate-red-2.yaml filter-saturate-red-2-ref.yaml
--- a/gfx/wr/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wr/wrench/src/yaml_frame_reader.rs
@@ -1820,29 +1820,27 @@ impl YamlFrameReader {
         if is_root {
             if let Some(size) = yaml["scroll-offset"].as_point() {
                 let external_id = ExternalScrollId(0, dl.pipeline_id);
                 self.scroll_offsets.insert(external_id, LayoutPoint::new(size.x, size.y));
             }
         }
 
         let filters = yaml["filters"].as_vec_filter_op().unwrap_or(vec![]);
-        let filter_datas = yaml["filter-datas"].as_vec_filter_data().unwrap_or(vec![]);
 
         info.rect = bounds;
         info.clip_rect = bounds;
 
         dl.push_stacking_context(
             &info,
             *self.spatial_id_stack.last().unwrap(),
             clip_node_id,
             transform_style,
             mix_blend_mode,
             &filters,
-            &filter_datas,
             raster_space,
             cache_tiles,
         );
 
         if !yaml["items"].is_badvalue() {
             self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]);
         }
 
--- a/gfx/wr/wrench/src/yaml_frame_writer.rs
+++ b/gfx/wr/wrench/src/yaml_frame_writer.rs
@@ -212,18 +212,16 @@ fn write_reference_frame(
     usize_node(parent, "id", clip_id_mapper.add_spatial_id(reference_frame.id));
 }
 
 fn write_stacking_context(
     parent: &mut Table,
     sc: &StackingContext,
     properties: &SceneProperties,
     filter_iter: AuxIter<FilterOp>,
-    filter_data_iter: &[TempFilterData],
-    display_list: &BuiltDisplayList,
 ) {
     enum_node(parent, "transform-style", sc.transform_style);
 
     let raster_space = match sc.raster_space {
         RasterSpace::Local(scale) => {
             format!("local({})", scale)
         }
         RasterSpace::Screen => {
@@ -263,60 +261,20 @@ fn write_stacking_context(
                 filters.push(Yaml::String(format!("color-matrix({:?})", matrix)))
             }
             FilterOp::SrgbToLinear => {
                 filters.push(Yaml::String("srgb-to-linear".to_string()))
             }
             FilterOp::LinearToSrgb => {
                 filters.push(Yaml::String("linear-to-srgb".to_string()))
             }
-            FilterOp::ComponentTransfer => {
-                filters.push(Yaml::String("component-transfer".to_string()))
-            }
         }
     }
 
     yaml_node(parent, "filters", Yaml::Array(filters));
-
-    // filter datas
-    let mut filter_datas = vec![];
-    for filter_data in filter_data_iter {
-        let func_types = display_list.get(filter_data.func_types).map(|func_type| {
-            match func_type {
-                ComponentTransferFuncType::Identity => { Yaml::String("Identity".to_string()) }
-                ComponentTransferFuncType::Table => { Yaml::String("Table".to_string()) }
-                ComponentTransferFuncType::Discrete => { Yaml::String("Discrete".to_string()) }
-                ComponentTransferFuncType::Linear => { Yaml::String("Linear".to_string()) }
-                ComponentTransferFuncType::Gamma => { Yaml::String("Gamma".to_string()) }
-            }
-        }).collect();
-        let r_values = display_list.get(filter_data.r_values).map(|value| {
-            Yaml::String(format!("{}", value))
-        }).collect();
-        let g_values = display_list.get(filter_data.g_values).map(|value| {
-            Yaml::String(format!("{}", value))
-        }).collect();
-        let b_values = display_list.get(filter_data.b_values).map(|value| {
-            Yaml::String(format!("{}", value))
-        }).collect();
-        let a_values = display_list.get(filter_data.a_values).map(|value| {
-            Yaml::String(format!("{}", value))
-        }).collect();
-
-        let avec: Vec<Yaml> = [
-            Yaml::Array(func_types),
-            Yaml::Array(r_values),
-            Yaml::Array(g_values),
-            Yaml::Array(b_values),
-            Yaml::Array(a_values),
-        ].to_vec();
-        filter_datas.push(Yaml::Array(avec));
-    }
-
-    yaml_node(parent, "filter-datas", Yaml::Array(filter_datas));
 }
 
 #[cfg(target_os = "macos")]
 fn native_font_handle_to_yaml(
     rsrc: &mut ResourceGenerator,
     handle: &NativeFontHandle,
     parent: &mut yaml_rust::yaml::Hash,
     path_opt: &mut Option<PathBuf>,
@@ -1071,18 +1029,16 @@ impl YamlFrameWriter {
                 Sdi::PushStackingContext(item) => {
                     str_node(&mut v, "type", "stacking-context");
                     let filters = display_list.get(base.filters());
                     write_stacking_context(
                         &mut v,
                         &item.stacking_context,
                         &scene.properties,
                         filters,
-                        base.filter_datas(),
-                        display_list,
                     );
 
                     let mut sub_iter = base.sub_iter();
                     self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper);
                     continue_traversal = Some(sub_iter);
                 }
                 Sdi::PushReferenceFrame(item) => {
                     str_node(&mut v, "type", "reference-frame");
@@ -1191,18 +1147,16 @@ impl YamlFrameWriter {
                 Sdi::PopStackingContext => return,
 
                 Sdi::PopCacheMarker => return,
                 Sdi::PushCacheMarker(_) => {
                     str_node(&mut v, "type", "cache-marker");
                 }
 
                 Sdi::SetGradientStops => panic!("dummy item yielded?"),
-                Sdi::SetFilterOps => panic!("dummy item yielded?"),
-                Sdi::SetFilterData => panic!("dummy item yielded?"),
                 Sdi::PushShadow(shadow) => {
                     str_node(&mut v, "type", "shadow");
                     vector_node(&mut v, "offset", &shadow.offset);
                     color_node(&mut v, "color", shadow.color);
                     f32_node(&mut v, "blur-radius", shadow.blur_radius);
                 }
                 Sdi::PopAllShadows => {
                     str_node(&mut v, "type", "pop-all-shadows");
--- a/gfx/wr/wrench/src/yaml_helper.rs
+++ b/gfx/wr/wrench/src/yaml_helper.rs
@@ -31,18 +31,16 @@ pub trait YamlHelper {
     fn as_border_radius_component(&self) -> LayoutSize;
     fn as_border_radius(&self) -> Option<BorderRadius>;
     fn as_transform_style(&self) -> Option<TransformStyle>;
     fn as_raster_space(&self) -> Option<RasterSpace>;
     fn as_clip_mode(&self) -> Option<ClipMode>;
     fn as_mix_blend_mode(&self) -> Option<MixBlendMode>;
     fn as_filter_op(&self) -> Option<FilterOp>;
     fn as_vec_filter_op(&self) -> Option<Vec<FilterOp>>;
-    fn as_filter_data(&self) -> Option<FilterData>;
-    fn as_vec_filter_data(&self) -> Option<Vec<FilterData>>;
 }
 
 fn string_to_color(color: &str) -> Option<ColorF> {
     match color {
         "red" => Some(ColorF::new(1.0, 0.0, 0.0, 1.0)),
         "green" => Some(ColorF::new(0.0, 1.0, 0.0, 1.0)),
         "blue" => Some(ColorF::new(0.0, 0.0, 1.0, 1.0)),
         "white" => Some(ColorF::new(1.0, 1.0, 1.0, 1.0)),
@@ -136,27 +134,16 @@ define_string_enum!(
         Dotted = "dotted",
         Dashed = "dashed",
         Wavy = "wavy"
     ]
 );
 
 define_string_enum!(ClipMode, [Clip = "clip", ClipOut = "clip-out"]);
 
-define_string_enum!(
-    ComponentTransferFuncType,
-    [
-        Identity = "Identity",
-        Table = "Table",
-        Discrete = "Discrete",
-        Linear = "Linear",
-        Gamma = "Gamma"
-    ]
-);
-
 // Rotate around `axis` by `degrees` angle
 fn make_rotation(
     origin: &LayoutPoint,
     degrees: f32,
     axis_x: f32,
     axis_y: f32,
     axis_z: f32,
 ) -> LayoutTransform {
@@ -556,19 +543,16 @@ impl YamlHelper for Yaml {
     }
 
     fn as_filter_op(&self) -> Option<FilterOp> {
         if let Some(s) = self.as_str() {
             match parse_function(s) {
                 ("identity", _, _) => {
                     Some(FilterOp::Identity)
                 }
-                ("component-transfer", _, _) => {
-                    Some(FilterOp::ComponentTransfer)
-                }
                 ("blur", ref args, _) if args.len() == 1 => {
                     Some(FilterOp::Blur(args[0].parse().unwrap()))
                 }
                 ("brightness", ref args, _) if args.len() == 1 => {
                     Some(FilterOp::Brightness(args[0].parse().unwrap()))
                 }
                 ("contrast", ref args, _) if args.len() == 1 => {
                     Some(FilterOp::Contrast(args[0].parse().unwrap()))
@@ -617,57 +601,9 @@ impl YamlHelper for Yaml {
 
     fn as_vec_filter_op(&self) -> Option<Vec<FilterOp>> {
         if let Some(v) = self.as_vec() {
             Some(v.iter().map(|x| x.as_filter_op().unwrap()).collect())
         } else {
             self.as_filter_op().map(|op| vec![op])
         }
     }
-
-    fn as_filter_data(&self) -> Option<FilterData> {
-        // Parse an array with five entries. First entry is an array of func types (4).
-        // The remaining entries are arrays of floats.
-        if let Yaml::Array(ref array) = *self {
-            if array.len() != 5 {
-                panic!("Invalid filter data specified, base array doesn't have five entries: {:?}", self);
-            }
-            if let Some(func_types_p) = array[0].as_vec_string() {
-                if func_types_p.len() != 4 {
-                    panic!("Invalid filter data specified, func type array doesn't have five entries: {:?}", self);
-                }
-                let func_types: Vec<ComponentTransferFuncType> =
-                    func_types_p.into_iter().map(|x| { match StringEnum::from_str(&x) {
-                        Some(y) => y,
-                        None => panic!("Invalid filter data specified, invalid func type name: {:?}", self),
-                    }}).collect();
-                if let Some(r_values_p) = array[1].as_vec_f32() {
-                    if let Some(g_values_p) = array[2].as_vec_f32() {
-                        if let Some(b_values_p) = array[3].as_vec_f32() {
-                            if let Some(a_values_p) = array[4].as_vec_f32() {
-                                let filter_data = FilterData {
-                                    func_r_type: func_types[0],
-                                    r_values: r_values_p,
-                                    func_g_type: func_types[1],
-                                    g_values: g_values_p,
-                                    func_b_type: func_types[2],
-                                    b_values: b_values_p,
-                                    func_a_type: func_types[3],
-                                    a_values: a_values_p,
-                                };
-                                return Some(filter_data)
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        None
-    }
-
-    fn as_vec_filter_data(&self) -> Option<Vec<FilterData>> {
-        if let Some(v) = self.as_vec() {
-            Some(v.iter().map(|x| x.as_filter_data().unwrap()).collect())
-        } else {
-            self.as_filter_data().map(|data| vec![data])
-        }
-    }
 }
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6069,17 +6069,17 @@ void PresShell::Paint(nsView* aViewToPai
 
   if (layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
     nsPresContext* pc = GetPresContext();
     LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
         pc->GetVisibleArea(), pc->AppUnitsPerDevPixel());
     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
     WebRenderBackgroundData data(wr::ToLayoutRect(bounds),
                                  wr::ToColorF(ToDeviceColor(bgcolor)));
-    WrFiltersHolder wrFilters;
+    nsTArray<wr::FilterOp> wrFilters;
 
     MaybeSetupTransactionIdAllocator(layerManager, presContext);
     layerManager->AsWebRenderLayerManager()->EndTransactionWithoutLayer(
         nullptr, nullptr, std::move(wrFilters), &data);
     return;
   }
 
   RefPtr<ColorLayer> root = layerManager->CreateColorLayer();
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2599,21 +2599,21 @@ already_AddRefed<LayerManager> nsDisplay
         }
         // This must be called even if PluginGeometryUpdates were not computed.
         rootPresContext->CollectPluginGeometryUpdates(layerManager);
       }
 
       auto* wrManager = static_cast<WebRenderLayerManager*>(layerManager.get());
 
       nsIDocShell* docShell = presContext->GetDocShell();
-      WrFiltersHolder wrFilters;
+      nsTArray<wr::FilterOp> wrFilters;
       gfx::Matrix5x4* colorMatrix =
           nsDocShell::Cast(docShell)->GetColorMatrix();
       if (colorMatrix) {
-        wrFilters.filters.AppendElement(
+        wrFilters.AppendElement(
             wr::FilterOp::ColorMatrix(colorMatrix->components));
       }
 
       wrManager->EndTransactionWithoutLayer(this, aBuilder,
                                             std::move(wrFilters));
     }
 
     // For layers-free mode, we check the invalidation state bits in the
@@ -9316,70 +9316,70 @@ void nsDisplayFilters::PaintAsLayer(nsDi
 }
 
 static float ClampStdDeviation(float aStdDeviation) {
   // Cap software blur radius for performance reasons.
   return std::min(std::max(0.0f, aStdDeviation), 100.0f);
 }
 
 bool nsDisplayFilters::CreateWebRenderCSSFilters(
-    WrFiltersHolder& wrFilters) {
+    nsTArray<mozilla::wr::FilterOp>& wrFilters) {
   // All CSS filters are supported by WebRender. SVG filters are not fully
   // supported, those use NS_STYLE_FILTER_URL and are handled separately.
   const nsTArray<nsStyleFilter>& filters = mFrame->StyleEffects()->mFilters;
 
   // If there are too many filters to render, then just pretend that we
   // succeeded, and don't render any of them.
   if (filters.Length() > gfxPrefs::WebRenderMaxFilterOpsPerChain()) {
     return true;
   }
-  wrFilters.filters.SetCapacity(filters.Length());
+  wrFilters.SetCapacity(filters.Length());
 
   for (const nsStyleFilter& filter : filters) {
     switch (filter.GetType()) {
       case NS_STYLE_FILTER_BRIGHTNESS:
-        wrFilters.filters.AppendElement(wr::FilterOp::Brightness(
+        wrFilters.AppendElement(wr::FilterOp::Brightness(
             filter.GetFilterParameter().GetFactorOrPercentValue()));
         break;
       case NS_STYLE_FILTER_CONTRAST:
-        wrFilters.filters.AppendElement(wr::FilterOp::Contrast(
+        wrFilters.AppendElement(wr::FilterOp::Contrast(
             filter.GetFilterParameter().GetFactorOrPercentValue()));
         break;
       case NS_STYLE_FILTER_GRAYSCALE:
-        wrFilters.filters.AppendElement(wr::FilterOp::Grayscale(
+        wrFilters.AppendElement(wr::FilterOp::Grayscale(
             filter.GetFilterParameter().GetFactorOrPercentValue()));
         break;
       case NS_STYLE_FILTER_INVERT:
-        wrFilters.filters.AppendElement(wr::FilterOp::Invert(
+        wrFilters.AppendElement(wr::FilterOp::Invert(
             filter.GetFilterParameter().GetFactorOrPercentValue()));
         break;
       case NS_STYLE_FILTER_OPACITY: {
         float opacity = filter.GetFilterParameter().GetFactorOrPercentValue();
-        wrFilters.filters.AppendElement(wr::FilterOp::Opacity(
+        wrFilters.AppendElement(wr::FilterOp::Opacity(
             wr::PropertyBinding<float>::Value(opacity), opacity));
         break;
       }
       case NS_STYLE_FILTER_SATURATE:
-        wrFilters.filters.AppendElement(wr::FilterOp::Saturate(
+        wrFilters.AppendElement(wr::FilterOp::Saturate(
             filter.GetFilterParameter().GetFactorOrPercentValue()));
         break;
       case NS_STYLE_FILTER_SEPIA: {
-        wrFilters.filters.AppendElement(wr::FilterOp::Sepia(
+        wrFilters.AppendElement(wr::FilterOp::Sepia(
             filter.GetFilterParameter().GetFactorOrPercentValue()));
         break;
       }
       case NS_STYLE_FILTER_HUE_ROTATE: {
-        wrFilters.filters.AppendElement(wr::FilterOp::HueRotate(
+        wrFilters.AppendElement(wr::FilterOp::HueRotate(
             (float)filter.GetFilterParameter().GetAngleValueInDegrees()));
         break;
       }
       case NS_STYLE_FILTER_BLUR: {
         float appUnitsPerDevPixel =
             mFrame->PresContext()->AppUnitsPerDevPixel();
-        wrFilters.filters.AppendElement(mozilla::wr::FilterOp::Blur(ClampStdDeviation(
+        wrFilters.AppendElement(mozilla::wr::FilterOp::Blur(ClampStdDeviation(
             NSAppUnitsToFloatPixels(filter.GetFilterParameter().GetCoordValue(),
                                     appUnitsPerDevPixel))));
         break;
       }
       case NS_STYLE_FILTER_DROP_SHADOW: {
         float appUnitsPerDevPixel =
             mFrame->PresContext()->AppUnitsPerDevPixel();
         nsCSSShadowArray* shadows = filter.GetDropShadow();
@@ -9401,30 +9401,30 @@ bool nsDisplayFilters::CreateWebRenderCS
             NSAppUnitsToFloatPixels(shadow->mRadius, appUnitsPerDevPixel),
             {
                 NS_GET_R(color) / 255.0f,
                 NS_GET_G(color) / 255.0f,
                 NS_GET_B(color) / 255.0f,
                 NS_GET_A(color) / 255.0f,
             });
 
-        wrFilters.filters.AppendElement(filterOp);
+        wrFilters.AppendElement(filterOp);
         break;
       }
       default:
         return false;
     }
   }
 
   return true;
 }
 
 bool nsDisplayFilters::CanCreateWebRenderCommands(
     nsDisplayListBuilder* aBuilder) {
-  WrFiltersHolder wrFilters;
+  nsTArray<mozilla::wr::FilterOp> wrFilters;
   Maybe<nsRect> filterClip;
   if (!CreateWebRenderCSSFilters(wrFilters) &&
       !nsSVGIntegrationUtils::BuildWebRenderFilters(mFrame, wrFilters,
                                                     filterClip)) {
     return false;
   }
   return true;
 }
@@ -9432,17 +9432,17 @@ bool nsDisplayFilters::CanCreateWebRende
 bool nsDisplayFilters::CreateWebRenderCommands(
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const StackingContextHelper& aSc,
     mozilla::layers::RenderRootStateManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) {
   float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
 
-  WrFiltersHolder wrFilters;
+  nsTArray<mozilla::wr::FilterOp> wrFilters;
   Maybe<nsRect> filterClip;
   if (!CreateWebRenderCSSFilters(wrFilters) &&
       !nsSVGIntegrationUtils::BuildWebRenderFilters(mFrame, wrFilters,
                                                     filterClip)) {
     return false;
   }
 
   wr::WrStackingContextClip clip;
@@ -9453,18 +9453,17 @@ bool nsDisplayFilters::CreateWebRenderCo
         aBuilder.DefineClip(Nothing(), wr::ToRoundedLayoutRect(devPxRect));
     clip = wr::WrStackingContextClip::ClipId(clipId);
   } else {
     clip = wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   }
 
   float opacity = mFrame->StyleEffects()->mOpacity;
   wr::StackingContextParams params;
-  params.mFilters = std::move(wrFilters.filters);
-  params.mFilterDatas = std::move(wrFilters.filter_datas);
+  params.mFilters = std::move(wrFilters);
   params.opacity = opacity != 1.0f && mHandleOpacity ? &opacity : nullptr;
   params.clip = clip;
   StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
                            params);
 
   nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, sc,
                                                 aManager, aDisplayListBuilder);
 
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -59,17 +59,16 @@ class nsIContent;
 class nsDisplayList;
 class nsDisplayTableItem;
 class nsIScrollableFrame;
 class nsSubDocumentFrame;
 class nsDisplayCompositorHitTestInfo;
 class nsDisplayScrollInfoLayer;
 class nsCaret;
 enum class nsDisplayOwnLayerFlags;
-struct WrFiltersHolder;
 
 namespace mozilla {
 class FrameLayerBuilder;
 struct MotionPathData;
 namespace layers {
 struct FrameMetrics;
 class RenderRootStateManager;
 class Layer;
@@ -6385,17 +6384,17 @@ class nsDisplayFilters : public nsDispla
   bool CreateWebRenderCommands(
       mozilla::wr::DisplayListBuilder& aBuilder,
       mozilla::wr::IpcResourceUpdateQueue& aResources,
       const StackingContextHelper& aSc,
       mozilla::layers::RenderRootStateManager* aManager,
       nsDisplayListBuilder* aDisplayListBuilder) override;
   bool CanCreateWebRenderCommands(nsDisplayListBuilder* aBuilder);
 
-  bool CreateWebRenderCSSFilters(WrFiltersHolder& wrFilters);
+  bool CreateWebRenderCSSFilters(nsTArray<mozilla::wr::FilterOp>& wrFilters);
 
  private:
   // relative to mFrame
   nsRect mEffectsBounds;
 };
 
 /* A display item that applies a transformation to all of its descendant
  * elements.  This wrapper should only be used if there is a transform applied
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -90,42 +90,20 @@ void nsFilterInstance::PaintFilteredFram
                             *metrics, filterChain, /* InputIsTainted */ true,
                             aPaintCallback, scaleMatrixInDevUnits, aDirtyArea,
                             nullptr, nullptr, nullptr);
   if (instance.IsInitialized()) {
     instance.Render(aCtx, aImgParams, aOpacity);
   }
 }
 
-static mozilla::wr::ComponentTransferFuncType
-FuncTypeToWr(uint8_t aFuncType) {
-  switch (aFuncType) {
-    case SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY:
-      return mozilla::wr::ComponentTransferFuncType::Identity;
-    case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
-      return mozilla::wr::ComponentTransferFuncType::Table;
-    case SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE:
-      return mozilla::wr::ComponentTransferFuncType::Discrete;
-    case SVG_FECOMPONENTTRANSFER_TYPE_LINEAR:
-      return mozilla::wr::ComponentTransferFuncType::Linear;
-    case SVG_FECOMPONENTTRANSFER_TYPE_GAMMA:
-      return mozilla::wr::ComponentTransferFuncType::Gamma;
-    default:
-      MOZ_ASSERT(false, "unknown func type?");
-  }
-  MOZ_ASSERT(false, "unknown func type?");
-  return mozilla::wr::ComponentTransferFuncType::Identity;
-}
-
 bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
-                                             WrFiltersHolder& aWrFilters,
+                                             nsTArray<wr::FilterOp>& aWrFilters,
                                              Maybe<nsRect>& aPostFilterClip) {
-  aWrFilters.filters.Clear();
-  aWrFilters.filter_datas.Clear();
-  aWrFilters.values.Clear();
+  aWrFilters.Clear();
 
   auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
   UniquePtr<UserSpaceMetrics> metrics =
       UserSpaceMetricsForFrame(aFilteredFrame);
 
   // TODO: simply using an identity matrix here, was pulling the scale from a
   // gfx context for the non-wr path.
   gfxMatrix scaleMatrix;
@@ -179,29 +157,29 @@ bool nsFilterInstance::BuildWebRenderFil
       }
     } else if (primitive.InputPrimitiveIndex(0) != int32_t(i - 1)) {
       return false;
     }
 
     bool previousSrgb = srgb;
     bool primNeedsSrgb = primitive.InputColorSpace(0) == gfx::ColorSpace::SRGB;
     if (srgb && !primNeedsSrgb) {
-      aWrFilters.filters.AppendElement(wr::FilterOp::SrgbToLinear());
+      aWrFilters.AppendElement(wr::FilterOp::SrgbToLinear());
     } else if (!srgb && primNeedsSrgb) {
-      aWrFilters.filters.AppendElement(wr::FilterOp::LinearToSrgb());
+      aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb());
     }
     srgb = primitive.OutputColorSpace() == gfx::ColorSpace::SRGB;
 
     const PrimitiveAttributes& attr = primitive.Attributes();
 
     bool filterIsNoop = false;
 
     if (attr.is<OpacityAttributes>()) {
       float opacity = attr.as<OpacityAttributes>().mOpacity;
-      aWrFilters.filters.AppendElement(wr::FilterOp::Opacity(
+      aWrFilters.AppendElement(wr::FilterOp::Opacity(
           wr::PropertyBinding<float>::Value(opacity), opacity));
     } else if (attr.is<ColorMatrixAttributes>()) {
       const ColorMatrixAttributes& attributes =
           attr.as<ColorMatrixAttributes>();
 
       float transposed[20];
       if (!gfx::ComputeColorMatrix(attributes, transposed)) {
         filterIsNoop = true;
@@ -224,17 +202,17 @@ bool nsFilterInstance::BuildWebRenderFil
 
       float matrix[20] = {
           transposed[0], transposed[5], transposed[10], transposed[15],
           transposed[1], transposed[6], transposed[11], transposed[16],
           transposed[2], transposed[7], transposed[12], transposed[17],
           transposed[3], transposed[8], transposed[13], transposed[18],
           transposed[4], transposed[9], transposed[14], transposed[19]};
 
-      aWrFilters.filters.AppendElement(wr::FilterOp::ColorMatrix(matrix));
+      aWrFilters.AppendElement(wr::FilterOp::ColorMatrix(matrix));
     } else if (attr.is<GaussianBlurAttributes>()) {
       if (finalClip) {
         // There's a clip that needs to apply before the blur filter, but
         // WebRender only lets us apply the clip at the end of the filter
         // chain. Clipping after a blur is not equivalent to clipping before
         // a blur, so bail out.
         return false;
       }
@@ -243,17 +221,17 @@ bool nsFilterInstance::BuildWebRenderFil
 
       const Size& stdDev = blur.mStdDeviation;
       if (stdDev.width != stdDev.height) {
         return false;
       }
 
       float radius = stdDev.width;
       if (radius != 0.0) {
-        aWrFilters.filters.AppendElement(wr::FilterOp::Blur(radius));
+        aWrFilters.AppendElement(wr::FilterOp::Blur(radius));
       } else {
         filterIsNoop = true;
       }
     } else if (attr.is<DropShadowAttributes>()) {
       if (finalClip) {
         // We have to bail out for the same reason we would with a blur filter.
         return false;
       }
@@ -272,93 +250,47 @@ bool nsFilterInstance::BuildWebRenderFil
       if (!primNeedsSrgb) {
         color = Color(gsRGBToLinearRGBMap[uint8_t(color.r * 255)],
                       gsRGBToLinearRGBMap[uint8_t(color.g * 255)],
                       gsRGBToLinearRGBMap[uint8_t(color.b * 255)], color.a);
       }
       wr::FilterOp filterOp = wr::FilterOp::DropShadow(
           offset, radius, wr::ToColorF(ToDeviceColor(color)));
 
-      aWrFilters.filters.AppendElement(filterOp);
-    } else if (attr.is<ComponentTransferAttributes>()) {
-      const ComponentTransferAttributes& attributes =
-          attr.as<ComponentTransferAttributes>();
-
-      size_t numValues = attributes.mValues[0].Length() +
-          attributes.mValues[1].Length() + attributes.mValues[2].Length() +
-          attributes.mValues[3].Length();
-      if (numValues > 1024) {
-        // Depending on how the wr shaders are implemented we may need to
-        // limit the total number of values.
-        return false;
-      }
-
-      wr::FilterOp filterOp = {wr::FilterOp::Tag::ComponentTransfer};
-      wr::WrFilterData filterData;
-      aWrFilters.values.AppendElement(nsTArray<float>());
-      nsTArray<float>* values = &aWrFilters.values[aWrFilters.values.Length()-1];
-      values->SetCapacity(numValues);
-
-      filterData.funcR_type = FuncTypeToWr(attributes.mTypes[0]);
-      size_t R_startindex = values->Length();
-      values->AppendElements(attributes.mValues[0]);
-      filterData.R_values_count = attributes.mValues[0].Length();
-
-      filterData.funcG_type = FuncTypeToWr(attributes.mTypes[1]);
-      size_t G_startindex = values->Length();
-      values->AppendElements(attributes.mValues[1]);
-      filterData.G_values_count = attributes.mValues[1].Length();
-
-      filterData.funcB_type = FuncTypeToWr(attributes.mTypes[2]);
-      size_t B_startindex = values->Length();
-      values->AppendElements(attributes.mValues[2]);
-      filterData.B_values_count = attributes.mValues[2].Length();
-
-      filterData.funcA_type = FuncTypeToWr(attributes.mTypes[3]);
-      size_t A_startindex = values->Length();
-      values->AppendElements(attributes.mValues[3]);
-      filterData.A_values_count = attributes.mValues[3].Length();
-
-      filterData.R_values = filterData.R_values_count > 0 ? &((*values)[R_startindex]) : nullptr;
-      filterData.G_values = filterData.G_values_count > 0 ? &((*values)[G_startindex]) : nullptr;
-      filterData.B_values = filterData.B_values_count > 0 ? &((*values)[B_startindex]) : nullptr;
-      filterData.A_values = filterData.A_values_count > 0 ? &((*values)[A_startindex]) : nullptr;
-
-      aWrFilters.filters.AppendElement(filterOp);
-      aWrFilters.filter_datas.AppendElement(filterData);
+      aWrFilters.AppendElement(filterOp);
     } else {
       return false;
     }
 
-    if (filterIsNoop && aWrFilters.filters.Length() > 0 &&
-        (aWrFilters.filters.LastElement().tag == wr::FilterOp::Tag::SrgbToLinear ||
-         aWrFilters.filters.LastElement().tag == wr::FilterOp::Tag::LinearToSrgb)) {
+    if (filterIsNoop && aWrFilters.Length() > 0 &&
+        (aWrFilters.LastElement().tag == wr::FilterOp::Tag::SrgbToLinear ||
+         aWrFilters.LastElement().tag == wr::FilterOp::Tag::LinearToSrgb)) {
       // We pushed a color space conversion filter in prevision of applying
       // another filter which turned out to be a no-op, so the conversion is
       // unnecessary. Remove it from the filter list.
       // This is both an optimization and a way to pass the wptest
       // css/filter-effects/filter-scale-001.html for which the needless
       // sRGB->linear->no-op->sRGB roundtrip introduces a slight error and we
       // cannot add fuzziness to the test.
-      Unused << aWrFilters.filters.PopLastElement();
+      Unused << aWrFilters.PopLastElement();
       srgb = previousSrgb;
     }
 
     if (!filterIsNoop) {
       if (finalClip.isNothing()) {
         finalClip = Some(primitive.PrimitiveSubregion());
       } else {
         finalClip =
             Some(primitive.PrimitiveSubregion().Intersect(finalClip.value()));
       }
     }
   }
 
   if (!srgb) {
-    aWrFilters.filters.AppendElement(wr::FilterOp::LinearToSrgb());
+    aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb());
   }
 
   if (finalClip) {
     aPostFilterClip = Some(instance.FilterSpaceToFrameSpace(finalClip.value()));
   }
   return true;
 }
 
--- a/layout/svg/nsFilterInstance.h
+++ b/layout/svg/nsFilterInstance.h
@@ -118,17 +118,17 @@ class nsFilterInstance {
                                     const gfxRect* aOverrideBBox = nullptr,
                                     const nsRect* aPreFilterBounds = nullptr);
 
   /**
    * Try to build WebRender filters for a frame if the filters applied to it are
    * supported.
    */
   static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
-                                    WrFiltersHolder& aWrFilters,
+                                    nsTArray<mozilla::wr::FilterOp>& aWrFilters,
                                     mozilla::Maybe<nsRect>& aPostFilterClip);
 
  private:
   /**
    * @param aTargetFrame The frame of the filtered element under consideration,
    *   may be null.
    * @param aTargetContent The filtered element itself.
    * @param aMetrics The metrics to resolve SVG lengths against.
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -1081,17 +1081,17 @@ void nsSVGIntegrationUtils::PaintFilter(
                                      offsets.offsetToUserSpaceInDevPx);
   nsRegion dirtyRegion = aParams.dirtyRect - offsets.offsetToBoundingBox;
 
   nsFilterInstance::PaintFilteredFrame(frame, &context, &callback, &dirtyRegion,
                                        aParams.imgParams, opacity);
 }
 
 bool nsSVGIntegrationUtils::BuildWebRenderFilters(
-    nsIFrame* aFilteredFrame, WrFiltersHolder& aWrFilters,
+    nsIFrame* aFilteredFrame, nsTArray<mozilla::wr::FilterOp>& aWrFilters,
     Maybe<nsRect>& aPostFilterClip) {
   return nsFilterInstance::BuildWebRenderFilters(aFilteredFrame, aWrFilters,
                                                  aPostFilterClip);
 }
 
 class PaintFrameCallback : public gfxDrawingCallback {
  public:
   PaintFrameCallback(nsIFrame* aFrame, const nsSize aPaintServerSize,
--- a/layout/svg/nsSVGIntegrationUtils.h
+++ b/layout/svg/nsSVGIntegrationUtils.h
@@ -29,23 +29,16 @@ class DrawTarget;
 namespace layers {
 class LayerManager;
 }  // namespace layers
 }  // namespace mozilla
 
 struct nsPoint;
 struct nsSize;
 
-struct WrFiltersHolder {
-  nsTArray<mozilla::wr::FilterOp> filters;
-  nsTArray<mozilla::wr::WrFilterData> filter_datas;
-  // This exists just to own the values long enough for them to be copied into rust.
-  nsTArray<nsTArray<float>> values;
-};
-
 /**
  * Integration of SVG effects (clipPath clipping, masking and filters) into
  * regular display list based painting and hit-testing.
  */
 class nsSVGIntegrationUtils final {
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::IntRect IntRect;
   typedef mozilla::image::imgDrawingParams imgDrawingParams;
@@ -198,17 +191,17 @@ class nsSVGIntegrationUtils final {
    */
   static void PaintFilter(const PaintFramesParams& aParams);
 
   /**
    * Try to build WebRender filters for a frame if the filters applied to it are
    * supported.
    */
   static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
-                                    WrFiltersHolder& aWrFilters,
+                                    nsTArray<mozilla::wr::FilterOp>& aWrFilters,
                                     mozilla::Maybe<nsRect>& aPostFilterClip);
 
   /**
    * @param aRenderingContext the target rendering context in which the paint
    * server will be rendered
    * @param aTarget the target frame onto which the paint server will be
    * rendered
    * @param aPaintServer a first-continuation frame to use as the source