From 0b1a68a2ad2e9b0876d6e371095e6d270a837ef7 Mon Sep 17 00:00:00 2001 From: shindli Date: Wed, 11 Mar 2020 10:36:47 +0200 Subject: [PATCH] Backed out 2 changesets (bug 1618000) for causing reftest failures in feGaussianBlur-5-ref.svg CLOSED TREE Backed out changeset a561435c24cf (bug 1618000) Backed out changeset e720691ccf17 (bug 1618000) --- gfx/wr/webrender/src/box_shadow.rs | 5 +- gfx/wr/webrender/src/frame_builder.rs | 1 - gfx/wr/webrender/src/internal_types.rs | 18 ++- gfx/wr/webrender/src/picture.rs | 139 +++++++----------- gfx/wr/webrender/src/prim_store/mod.rs | 3 +- gfx/wr/webrender/src/scene_building.rs | 5 +- gfx/wr/webrender_api/src/display_item.rs | 20 ++- .../filters/filter-blur-clamping-ref.yaml | 18 --- .../filters/filter-blur-clamping.yaml | 30 ---- .../filter-drop-shadow-blur-clamping-ref.yaml | 18 --- .../filter-drop-shadow-blur-clamping.yaml | 30 ---- .../filter-drop-shadow-transform-huge.yaml | 4 +- gfx/wr/wrench/reftests/filters/reftest.list | 2 - layout/svg/nsSVGIntegrationUtils.cpp | 11 +- 14 files changed, 104 insertions(+), 200 deletions(-) delete mode 100644 gfx/wr/wrench/reftests/filters/filter-blur-clamping-ref.yaml delete mode 100644 gfx/wr/wrench/reftests/filters/filter-blur-clamping.yaml delete mode 100644 gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping-ref.yaml delete mode 100644 gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping.yaml diff --git a/gfx/wr/webrender/src/box_shadow.rs b/gfx/wr/webrender/src/box_shadow.rs index c2ef077e8140..eb8d4d0d4e6d 100644 --- a/gfx/wr/webrender/src/box_shadow.rs +++ b/gfx/wr/webrender/src/box_shadow.rs @@ -4,6 +4,7 @@ use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, PrimitiveKeyKind}; use api::PropertyBinding; +use api::MAX_BLUR_RADIUS; use api::units::*; use crate::clip::{ClipItemKey, ClipItemKeyKind}; use crate::scene_building::SceneBuilder; @@ -50,10 +51,6 @@ pub struct BoxShadowClipSource { // The blur shader samples BLUR_SAMPLE_SCALE * blur_radius surrounding texels. pub const BLUR_SAMPLE_SCALE: f32 = 3.0; -// Maximum blur radius for box-shadows (different than blur filters). -// Taken from nsCSSRendering.cpp in Gecko. -pub const MAX_BLUR_RADIUS: f32 = 300.; - // A cache key that uniquely identifies a minimally sized // and blurred box-shadow rect that can be stored in the // texture cache and applied to clip-masks. diff --git a/gfx/wr/webrender/src/frame_builder.rs b/gfx/wr/webrender/src/frame_builder.rs index 803721dc66c9..deb2c9a5c34e 100644 --- a/gfx/wr/webrender/src/frame_builder.rs +++ b/gfx/wr/webrender/src/frame_builder.rs @@ -322,7 +322,6 @@ impl FrameBuilder { global_screen_world_rect, &scene.spatial_tree, global_device_pixel_scale, - (1.0, 1.0), ); surfaces.push(root_surface); diff --git a/gfx/wr/webrender/src/internal_types.rs b/gfx/wr/webrender/src/internal_types.rs index 5363f08c8154..1e8412bd698f 100644 --- a/gfx/wr/webrender/src/internal_types.rs +++ b/gfx/wr/webrender/src/internal_types.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{ColorF, DebugCommand, DocumentId, ExternalImageData, ExternalImageId, PrimitiveFlags}; -use api::{ImageFormat, ItemTag, NotificationRequest, Shadow, FilterOp}; +use api::{ImageFormat, ItemTag, NotificationRequest, Shadow, FilterOp, MAX_BLUR_RADIUS}; use api::units::*; use api; use crate::composite::NativeSurfaceOperation; @@ -86,6 +86,22 @@ pub enum Filter { } impl Filter { + /// Ensure that the parameters for a filter operation + /// are sensible. + pub fn sanitize(&mut self) { + match self { + Filter::Blur(ref mut radius) => { + *radius = radius.min(MAX_BLUR_RADIUS); + } + Filter::DropShadows(ref mut stack) => { + for shadow in stack { + shadow.blur_radius = shadow.blur_radius.min(MAX_BLUR_RADIUS); + } + } + _ => {}, + } + } + pub fn is_visible(&self) -> bool { match *self { Filter::Identity | diff --git a/gfx/wr/webrender/src/picture.rs b/gfx/wr/webrender/src/picture.rs index 670d20ad0da3..f4faf055fea5 100644 --- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -96,9 +96,9 @@ use api::{MixBlendMode, PipelineId, PremultipliedColorF, FilterPrimitiveKind}; use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FontRenderMode}; -use api::{DebugFlags, RasterSpace, ImageKey, ColorF, ColorU, PrimitiveFlags}; +use api::{DebugFlags, RasterSpace, ImageKey, ColorF, ColorU, PrimitiveFlags, MAX_BLUR_RADIUS}; use api::units::*; -use crate::box_shadow::BLUR_SAMPLE_SCALE; +use crate::box_shadow::{BLUR_SAMPLE_SCALE}; use crate::clip::{ClipStore, ClipChainInstance, ClipDataHandle, ClipChainId}; use crate::spatial_tree::{ROOT_SPATIAL_NODE_INDEX, SpatialTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace @@ -133,7 +133,7 @@ use smallvec::SmallVec; use std::{mem, u8, marker, u32}; use std::sync::atomic::{AtomicUsize, Ordering}; use crate::texture_cache::TextureCacheHandle; -use crate::util::{MaxRect, VecHelper, RectHelpers, MatrixHelpers}; +use crate::util::{MaxRect, scale_factors, VecHelper, RectHelpers, MatrixHelpers}; use crate::filterdata::{FilterDataHandle}; #[cfg(any(feature = "capture", feature = "replay"))] use ron; @@ -170,10 +170,6 @@ use crate::scene_building::{SliceFlags}; // used by tileview so don't use an internal_types FastHashMap use std::collections::HashMap; -// Maximum blur radius for blur filter (different than box-shadow blur). -// Taken from FilterNodeSoftware.cpp in Gecko. -pub const MAX_BLUR_RADIUS: f32 = 100.; - /// Specify whether a surface allows subpixel AA text rendering. #[derive(Debug, Clone, PartialEq)] pub enum SubpixelMode { @@ -403,20 +399,6 @@ fn clampf(value: f32, low: f32, high: f32) -> f32 { value.max(low).min(high) } -/// Clamps the blur radius depending on scale factors. -fn clamp_blur_radius(blur_radius: f32, scale_factors: (f32, f32)) -> f32 { - // Clamping must occur after scale factors are applied, but scale factors are not applied - // until later on. To clamp the blur radius, we first apply the scale factors and then clamp - // and finally revert the scale factors. - - // TODO: the clamping should be done on a per-axis basis, but WR currently only supports - // having a single value for both x and y blur. - let largest_scale_factor = f32::max(scale_factors.0, scale_factors.1); - let adjusted_blur_radius = blur_radius * largest_scale_factor; - let clamped_blur_radius = f32::min(adjusted_blur_radius, MAX_BLUR_RADIUS); - clamped_blur_radius / largest_scale_factor -} - /// An index into the prims array in a TileDescriptor. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "capture", derive(Serialize))] @@ -3753,8 +3735,6 @@ pub struct SurfaceInfo { pub inflation_factor: f32, /// The device pixel ratio specific to this surface. pub device_pixel_scale: DevicePixelScale, - /// The scale factors of the surface to raster transform. - pub scale_factors: (f32, f32), } impl SurfaceInfo { @@ -3765,7 +3745,6 @@ impl SurfaceInfo { world_rect: WorldRect, spatial_tree: &SpatialTree, device_pixel_scale: DevicePixelScale, - scale_factors: (f32, f32), ) -> Self { let map_surface_to_world = SpaceMapper::new_with_target( ROOT_SPATIAL_NODE_INDEX, @@ -3791,7 +3770,6 @@ impl SurfaceInfo { surface_spatial_node_index, inflation_factor, device_pixel_scale, - scale_factors, } } } @@ -3854,20 +3832,19 @@ pub enum PictureCompositeMode { } impl PictureCompositeMode { - pub fn inflate_picture_rect(&self, picture_rect: PictureRect, scale_factors: (f32, f32)) -> PictureRect { + pub fn inflate_picture_rect(&self, picture_rect: PictureRect, inflation_factor: f32) -> PictureRect { let mut result_rect = picture_rect; match self { PictureCompositeMode::Filter(filter) => match filter { - Filter::Blur(blur_radius) => { - let inflation_factor = clamp_blur_radius(*blur_radius, scale_factors).ceil() * BLUR_SAMPLE_SCALE; + Filter::Blur(_) => { result_rect = picture_rect.inflate(inflation_factor, inflation_factor); }, Filter::DropShadows(shadows) => { let mut max_inflation: f32 = 0.0; for shadow in shadows { - max_inflation = max_inflation.max(shadow.blur_radius); + let inflation_factor = shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE; + max_inflation = max_inflation.max(inflation_factor); } - max_inflation = clamp_blur_radius(max_inflation, scale_factors).ceil() * BLUR_SAMPLE_SCALE; result_rect = picture_rect.inflate(max_inflation, max_inflation); }, _ => {} @@ -4538,10 +4515,6 @@ impl PicturePrimitive { .surfaces[raster_config.surface_index.0] .device_pixel_scale; - let scale_factors = frame_state - .surfaces[raster_config.surface_index.0] - .scale_factors; - let (mut clipped, mut unclipped) = match get_raster_rects( pic_rect, &map_pic_to_raster, @@ -4615,14 +4588,15 @@ impl PicturePrimitive { let dep_info = match raster_config.composite_mode { PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => { - let blur_std_deviation = clamp_blur_radius(blur_radius, scale_factors) * device_pixel_scale.0; + let blur_std_deviation = blur_radius * device_pixel_scale.0; + let scale_factors = scale_factors(&transform); let mut blur_std_deviation = DeviceSize::new( blur_std_deviation * scale_factors.0, blur_std_deviation * scale_factors.1 ); let mut device_rect = if self.options.inflate_if_required { let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor; - let inflation_factor = inflation_factor * device_pixel_scale.0; + let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil(); // The clipped field is the part of the picture that is visible // on screen. The unclipped field is the screen-space rect of @@ -4635,7 +4609,7 @@ impl PicturePrimitive { // We cast clipped to f32 instead of casting unclipped to i32 // because unclipped can overflow an i32. let device_rect = clipped.to_f32() - .inflate(inflation_factor * scale_factors.0, inflation_factor * scale_factors.1) + .inflate(inflation_factor, inflation_factor) .intersection(&unclipped) .unwrap(); @@ -4708,15 +4682,14 @@ impl PicturePrimitive { for shadow in shadows { // TODO(nical) presumably we should compute the clipped rect for each shadow // and compute the union of them to determine what we need to rasterize and blur? - max_std_deviation = f32::max(max_std_deviation, shadow.blur_radius); + max_std_deviation = f32::max(max_std_deviation, shadow.blur_radius * device_pixel_scale.0); } - max_std_deviation = clamp_blur_radius(max_std_deviation, scale_factors) * device_pixel_scale.0; - let max_blur_range = max_std_deviation * BLUR_SAMPLE_SCALE; + let max_blur_range = (max_std_deviation * BLUR_SAMPLE_SCALE).ceil(); // We cast clipped to f32 instead of casting unclipped to i32 // because unclipped can overflow an i32. let device_rect = clipped.to_f32() - .inflate(max_blur_range * scale_factors.0, max_blur_range * scale_factors.1) + .inflate(max_blur_range, max_blur_range) .intersection(&unclipped) .unwrap(); @@ -4729,10 +4702,7 @@ impl PicturePrimitive { device_rect.size = RenderTask::adjusted_blur_source_size( device_rect.size, - DeviceSize::new( - max_std_deviation * scale_factors.0, - max_std_deviation * scale_factors.1 - ), + DeviceSize::new(max_std_deviation, max_std_deviation), ); if let Some(scale) = adjust_scale_for_max_surface_size( @@ -4776,12 +4746,14 @@ impl PicturePrimitive { self.extra_gpu_data_handles.resize(shadows.len(), GpuCacheHandle::new()); let mut blur_render_task_id = picture_task_id; + let scale_factors = scale_factors(&transform); for shadow in shadows { - let blur_radius = clamp_blur_radius(shadow.blur_radius, scale_factors) * device_pixel_scale.0; + // TODO(cbrewster): We should take the scale factors into account when clamping the max + // std deviation for the blur earlier so that we don't overinflate. blur_render_task_id = RenderTask::new_blur( DeviceSize::new( - blur_radius * scale_factors.0, - blur_radius * scale_factors.1, + f32::min(shadow.blur_radius * scale_factors.0, MAX_BLUR_RADIUS) * device_pixel_scale.0, + f32::min(shadow.blur_radius * scale_factors.1, MAX_BLUR_RADIUS) * device_pixel_scale.0, ), picture_task_id, frame_state.render_tasks, @@ -5601,6 +5573,33 @@ impl PicturePrimitive { let parent_raster_node_index = state.current_surface().raster_spatial_node_index; let surface_spatial_node_index = self.spatial_node_index; + // This inflation factor is to be applied to all primitives within the surface. + let inflation_factor = match composite_mode { + PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => { + // Only inflate if the caller hasn't already inflated + // the bounding rects for this filter. + if self.options.inflate_if_required { + // The amount of extra space needed for primitives inside + // this picture to ensure the visibility check is correct. + BLUR_SAMPLE_SCALE * blur_radius + } else { + 0.0 + } + } + PictureCompositeMode::SvgFilter(ref primitives, _) if self.options.inflate_if_required => { + let mut max = 0.0; + for primitive in primitives { + if let FilterPrimitiveKind::Blur(ref blur) = primitive.kind { + max = f32::max(max, blur.radius * BLUR_SAMPLE_SCALE); + } + } + max + } + _ => { + 0.0 + } + }; + // Filters must be applied before transforms, to do this, we can mark this picture as establishing a raster root. let has_svg_filter = if let PictureCompositeMode::SvgFilter(..) = composite_mode { true @@ -5614,49 +5613,17 @@ impl PicturePrimitive { .get_relative_transform(surface_spatial_node_index, parent_raster_node_index) .is_perspective(); - let raster_spatial_node_index = if establishes_raster_root { - surface_spatial_node_index - } else { - parent_raster_node_index - }; - - let scale_factors = frame_context - .spatial_tree - .get_relative_transform(surface_spatial_node_index, raster_spatial_node_index) - .scale_factors(); - - // This inflation factor is to be applied to all primitives within the surface. - // Only inflate if the caller hasn't already inflated the bounding rects for this filter. - let mut inflation_factor = 0.0; - if self.options.inflate_if_required { - match composite_mode { - PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => { - let blur_radius = clamp_blur_radius(blur_radius, scale_factors); - // The amount of extra space needed for primitives inside - // this picture to ensure the visibility check is correct. - inflation_factor = blur_radius * BLUR_SAMPLE_SCALE; - } - PictureCompositeMode::SvgFilter(ref primitives, _) => { - let mut max = 0.0; - for primitive in primitives { - if let FilterPrimitiveKind::Blur(ref blur) = primitive.kind { - max = f32::max(max, blur.radius); - } - } - inflation_factor = clamp_blur_radius(max, scale_factors) * BLUR_SAMPLE_SCALE; - } - _ => {} - } - } - let surface = SurfaceInfo::new( surface_spatial_node_index, - raster_spatial_node_index, + if establishes_raster_root { + surface_spatial_node_index + } else { + parent_raster_node_index + }, inflation_factor, frame_context.global_screen_world_rect, &frame_context.spatial_tree, frame_context.global_device_pixel_scale, - scale_factors, ); self.raster_config = Some(RasterConfig { @@ -5790,7 +5757,7 @@ impl PicturePrimitive { // Inflate the local bounding rect if required by the filter effect. // This inflaction factor is to be applied to the surface itself. if self.options.inflate_if_required { - surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.scale_factors); + surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.inflation_factor); // The picture's local rect is calculated as the union of the // snapped primitive rects, which should result in a snapped diff --git a/gfx/wr/webrender/src/prim_store/mod.rs b/gfx/wr/webrender/src/prim_store/mod.rs index f208710aa7c5..72e47fe458c1 100644 --- a/gfx/wr/webrender/src/prim_store/mod.rs +++ b/gfx/wr/webrender/src/prim_store/mod.rs @@ -2354,8 +2354,7 @@ impl PrimitiveStore { surface.device_pixel_scale, frame_context.spatial_tree, ); - - surface_rect = rc.composite_mode.inflate_picture_rect(surface_rect, surface.scale_factors); + surface_rect = rc.composite_mode.inflate_picture_rect(surface_rect, surface.inflation_factor); surface_rect = snap_pic_to_raster.snap_rect(&surface_rect); } diff --git a/gfx/wr/webrender/src/scene_building.rs b/gfx/wr/webrender/src/scene_building.rs index 02c5c2c1b90f..257c8c02d812 100644 --- a/gfx/wr/webrender/src/scene_building.rs +++ b/gfx/wr/webrender/src/scene_building.rs @@ -2566,7 +2566,8 @@ impl<'a> SceneBuilder<'a> { // blur radius is 0, the code in Picture::prepare_for_render will // detect this and mark the picture to be drawn directly into the // parent picture, which avoids an intermediate surface and blur. - let blur_filter = Filter::Blur(std_deviation); + let mut blur_filter = Filter::Blur(std_deviation); + blur_filter.sanitize(); let composite_mode = PictureCompositeMode::Filter(blur_filter); let composite_mode_key = Some(composite_mode.clone()).into(); @@ -3473,6 +3474,8 @@ impl<'a> SceneBuilder<'a> { // For each filter, create a new image with that composite mode. let mut current_filter_data_index = 0; for filter in &mut filter_ops { + filter.sanitize(); + let composite_mode = Some(match *filter { Filter::ComponentTransfer => { let filter_data = diff --git a/gfx/wr/webrender_api/src/display_item.rs b/gfx/wr/webrender_api/src/display_item.rs index a3eaec411583..c87249df6dfe 100644 --- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -12,6 +12,10 @@ use crate::color::ColorF; use crate::image::{ColorDepth, ImageKey}; use crate::units::*; +// Maximum blur radius. +// Taken from nsCSSRendering.cpp in Gecko. +pub const MAX_BLUR_RADIUS: f32 = 300.; + // ****************************************************************** // * NOTE: some of these structs have an "IMPLICIT" comment. * // * This indicates that the BuiltDisplayList will have serialized * @@ -871,6 +875,12 @@ pub struct BlurPrimitive { pub radius: f32, } +impl BlurPrimitive { + pub fn sanitize(&mut self) { + self.radius = self.radius.min(MAX_BLUR_RADIUS); + } +} + #[repr(C)] #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct OpacityPrimitive { @@ -899,6 +909,12 @@ pub struct DropShadowPrimitive { pub shadow: Shadow, } +impl DropShadowPrimitive { + pub fn sanitize(&mut self) { + self.shadow.blur_radius = self.shadow.blur_radius.min(MAX_BLUR_RADIUS); + } +} + #[repr(C)] #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] pub struct ComponentTransferPrimitive { @@ -956,7 +972,9 @@ impl FilterPrimitiveKind { pub fn sanitize(&mut self) { match self { FilterPrimitiveKind::Flood(flood) => flood.sanitize(), + FilterPrimitiveKind::Blur(blur) => blur.sanitize(), FilterPrimitiveKind::Opacity(opacity) => opacity.sanitize(), + FilterPrimitiveKind::DropShadow(drop_shadow) => drop_shadow.sanitize(), // No sanitization needed. FilterPrimitiveKind::Identity(..) | @@ -964,8 +982,6 @@ impl FilterPrimitiveKind { FilterPrimitiveKind::ColorMatrix(..) | FilterPrimitiveKind::Offset(..) | FilterPrimitiveKind::Composite(..) | - FilterPrimitiveKind::Blur(..) | - FilterPrimitiveKind::DropShadow(..) | // Component transfer's filter data is sanitized separately. FilterPrimitiveKind::ComponentTransfer(..) => {} } diff --git a/gfx/wr/wrench/reftests/filters/filter-blur-clamping-ref.yaml b/gfx/wr/wrench/reftests/filters/filter-blur-clamping-ref.yaml deleted file mode 100644 index cdc6c56a47b4..000000000000 --- a/gfx/wr/wrench/reftests/filters/filter-blur-clamping-ref.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Ensures that blur clamping happens after scale factors are applied ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 300, 300] - filters: blur(100) - items: - - type: rect - bounds: [0, 0, 100, 100] - color: 0 255 0 1.0 - - type: stacking-context - bounds: [400, 100, 300, 300] - filters: blur(50) - items: - - type: rect - bounds: [0, 0, 100, 100] - color: 255 0 0 1.0 diff --git a/gfx/wr/wrench/reftests/filters/filter-blur-clamping.yaml b/gfx/wr/wrench/reftests/filters/filter-blur-clamping.yaml deleted file mode 100644 index 614aa8ee02af..000000000000 --- a/gfx/wr/wrench/reftests/filters/filter-blur-clamping.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Ensures that blur clamping happens after scale factors are applied ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 300, 300] - transform: scale(10) - items: - - type: stacking-context - bounds: [0, 0, 300, 300] - # Blur will be 20 * 10(scale) = 200 and it should then be clamped to 100 - filters: blur(20) - items: - - type: rect - bounds: [0, 0, 10, 10] - color: 0 255 0 1.0 - - type: stacking-context - bounds: [400, 100, 300, 300] - transform: scale(0.1) - items: - - type: stacking-context - bounds: [0, 0, 300, 300] - # Blur should be 500 * 0.1(scale) = 50. This tests to make sure clamping - # does not occur before applying scale factors, otherwise 500 would be - # clamped to 100. - filters: blur(500) - items: - - type: rect - bounds: [0, 0, 1000, 1000] - color: 255 0 0 1.0 diff --git a/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping-ref.yaml b/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping-ref.yaml deleted file mode 100644 index 6ffcde5f5b99..000000000000 --- a/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping-ref.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Ensures that blur clamping happens after scale factors are applied ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 300, 300] - filters: drop-shadow([0, 0], 100, blue) - items: - - type: rect - bounds: [0, 0, 100, 100] - color: 0 255 0 1.0 - - type: stacking-context - bounds: [400, 100, 300, 300] - filters: drop-shadow([0, 0], 50, green) - items: - - type: rect - bounds: [0, 0, 100, 100] - color: 255 0 0 1.0 diff --git a/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping.yaml b/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping.yaml deleted file mode 100644 index 1d7157a8e63a..000000000000 --- a/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Ensures that blur clamping happens after scale factors are applied ---- -root: - items: - - type: stacking-context - bounds: [100, 100, 300, 300] - transform: scale(10) - items: - - type: stacking-context - bounds: [0, 0, 300, 300] - # Blur will be 20 * 10(scale) = 200 and it should then be clamped to 100 - filters: drop-shadow([0, 0], 20, blue) - items: - - type: rect - bounds: [0, 0, 10, 10] - color: 0 255 0 1.0 - - type: stacking-context - bounds: [400, 100, 300, 300] - transform: scale(0.1) - items: - - type: stacking-context - bounds: [0, 0, 300, 300] - # Blur should be 500 * 0.1(scale) = 50. This tests to make sure clamping - # does not occur before applying scale factors, otherwise 500 would be - # clamped to 100. - filters: drop-shadow([0, 0], 500, green) - items: - - type: rect - bounds: [0, 0, 1000, 1000] - color: 255 0 0 1.0 diff --git a/gfx/wr/wrench/reftests/filters/filter-drop-shadow-transform-huge.yaml b/gfx/wr/wrench/reftests/filters/filter-drop-shadow-transform-huge.yaml index e46af9dfa404..65c699f8fa39 100644 --- a/gfx/wr/wrench/reftests/filters/filter-drop-shadow-transform-huge.yaml +++ b/gfx/wr/wrench/reftests/filters/filter-drop-shadow-transform-huge.yaml @@ -7,11 +7,11 @@ root: items: - type: stacking-context bounds: [0, 0, 1000, 1000] - transform: scale-y(100) + transform: scale-y(999999.25) items: - type: stacking-context bounds: [0, 0, 1000, 1000] - filters: drop-shadow([0, 0], 999999, [255, 0, 0, 1]) + filters: drop-shadow([999999, 999999], 999999, [255, 0, 0, 1]) items: - image: checkerboard(2, 16, 16) bounds: [0, 0, 1000, 1000] diff --git a/gfx/wr/wrench/reftests/filters/reftest.list b/gfx/wr/wrench/reftests/filters/reftest.list index 0853d8fbc76e..7222c7b5c4e1 100644 --- a/gfx/wr/wrench/reftests/filters/reftest.list +++ b/gfx/wr/wrench/reftests/filters/reftest.list @@ -45,9 +45,7 @@ skip_on(android,device) == filter-mix-blend-mode.yaml filter-mix-blend-mode-ref. != filter-blur-huge.yaml blank.yaml != filter-drop-shadow-huge.yaml blank.yaml != filter-drop-shadow-transform-huge.yaml blank.yaml -== filter-drop-shadow-blur-clamping.yaml filter-drop-shadow-blur-clamping-ref.yaml == filter-blur-scaled.yaml filter-blur-scaled-ref.yaml -== filter-blur-clamping.yaml filter-blur-clamping-ref.yaml skip_on(android,device) fuzzy(1,104) == filter-blur-scaled-xonly.yaml filter-blur-scaled-xonly.png # fails on Pixel2 == svg-filter-component-transfer.yaml filter-component-transfer-ref.yaml == svg-filter-flood.yaml svg-filter-flood-ref.yaml diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index 0c53a34f7958..c3253cee74c9 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -1107,6 +1107,11 @@ void nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams) { aParams.imgParams, opacity); } +static float ClampStdDeviation(float aStdDeviation) { + // Cap software blur radius for performance reasons. + return std::min(std::max(0.0f, aStdDeviation), 100.0f); +} + bool nsSVGIntegrationUtils::CreateWebRenderCSSFilters( Span aFilters, nsIFrame* aFrame, WrFiltersHolder& aWrFilters) { @@ -1157,9 +1162,9 @@ bool nsSVGIntegrationUtils::CreateWebRenderCSSFilters( // TODO(emilio): we should go directly from css pixels -> device pixels. float appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); - wrFilters.AppendElement( - mozilla::wr::FilterOp::Blur(NSAppUnitsToFloatPixels( - filter.AsBlur().ToAppUnits(), appUnitsPerDevPixel))); + wrFilters.AppendElement(mozilla::wr::FilterOp::Blur( + ClampStdDeviation(NSAppUnitsToFloatPixels( + filter.AsBlur().ToAppUnits(), appUnitsPerDevPixel)))); break; } case StyleFilter::Tag::DropShadow: {