From 34e8ddc337a87ca5d3aac70360c8d8c7937de9c0 Mon Sep 17 00:00:00 2001 From: cbrewster Date: Mon, 23 Mar 2020 18:22:32 +0000 Subject: [PATCH] Bug 1618000: Part 2: Clamp blur radius based on scale factors r=gfx-reviewers,nical Differential Revision: https://phabricator.services.mozilla.com/D65805 --HG-- extra : moz-landing-system : lando --- 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/reftests/svg/filters/reftest.list | 2 +- 14 files changed, 198 insertions(+), 97 deletions(-) create mode 100644 gfx/wr/wrench/reftests/filters/filter-blur-clamping-ref.yaml create mode 100644 gfx/wr/wrench/reftests/filters/filter-blur-clamping.yaml create mode 100644 gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping-ref.yaml create 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 eb8d4d0d4e6d..c2ef077e8140 100644 --- a/gfx/wr/webrender/src/box_shadow.rs +++ b/gfx/wr/webrender/src/box_shadow.rs @@ -4,7 +4,6 @@ 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; @@ -51,6 +50,10 @@ 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 de399e768275..2942ba285532 100644 --- a/gfx/wr/webrender/src/frame_builder.rs +++ b/gfx/wr/webrender/src/frame_builder.rs @@ -323,6 +323,7 @@ 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 a7f9996a073f..11e760ac475f 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, MAX_BLUR_RADIUS}; +use api::{ImageFormat, ItemTag, NotificationRequest, Shadow, FilterOp}; use api::units::*; use api; use crate::composite::NativeSurfaceOperation; @@ -86,22 +86,6 @@ 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 c404ebf1fcd1..99cf9e76afa6 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, MAX_BLUR_RADIUS}; +use api::{DebugFlags, RasterSpace, ImageKey, ColorF, ColorU, PrimitiveFlags}; 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, scale_factors, VecHelper, RectHelpers, MatrixHelpers}; +use crate::util::{MaxRect, VecHelper, RectHelpers, MatrixHelpers}; use crate::filterdata::{FilterDataHandle}; #[cfg(any(feature = "capture", feature = "replay"))] use ron; @@ -170,6 +170,10 @@ 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 { @@ -399,6 +403,20 @@ 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))] @@ -3764,6 +3782,8 @@ 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 { @@ -3774,6 +3794,7 @@ 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, @@ -3799,6 +3820,7 @@ impl SurfaceInfo { surface_spatial_node_index, inflation_factor, device_pixel_scale, + scale_factors, } } } @@ -3861,19 +3883,20 @@ pub enum PictureCompositeMode { } impl PictureCompositeMode { - pub fn inflate_picture_rect(&self, picture_rect: PictureRect, inflation_factor: f32) -> PictureRect { + pub fn inflate_picture_rect(&self, picture_rect: PictureRect, scale_factors: (f32, f32)) -> PictureRect { let mut result_rect = picture_rect; match self { PictureCompositeMode::Filter(filter) => match filter { - Filter::Blur(_) => { + Filter::Blur(blur_radius) => { + let inflation_factor = clamp_blur_radius(*blur_radius, scale_factors).ceil() * BLUR_SAMPLE_SCALE; result_rect = picture_rect.inflate(inflation_factor, inflation_factor); }, Filter::DropShadows(shadows) => { let mut max_inflation: f32 = 0.0; for shadow in shadows { - let inflation_factor = shadow.blur_radius.ceil() * BLUR_SAMPLE_SCALE; - max_inflation = max_inflation.max(inflation_factor); + max_inflation = max_inflation.max(shadow.blur_radius); } + max_inflation = clamp_blur_radius(max_inflation, scale_factors).ceil() * BLUR_SAMPLE_SCALE; result_rect = picture_rect.inflate(max_inflation, max_inflation); }, _ => {} @@ -4544,6 +4567,10 @@ 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, @@ -4617,15 +4644,14 @@ impl PicturePrimitive { let dep_info = match raster_config.composite_mode { PictureCompositeMode::Filter(Filter::Blur(blur_radius)) => { - let blur_std_deviation = blur_radius * device_pixel_scale.0; - let scale_factors = scale_factors(&transform); + let blur_std_deviation = clamp_blur_radius(blur_radius, scale_factors) * device_pixel_scale.0; 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).ceil(); + let inflation_factor = inflation_factor * device_pixel_scale.0; // The clipped field is the part of the picture that is visible // on screen. The unclipped field is the screen-space rect of @@ -4638,7 +4664,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, inflation_factor) + .inflate(inflation_factor * scale_factors.0, inflation_factor * scale_factors.1) .intersection(&unclipped) .unwrap(); @@ -4711,14 +4737,15 @@ 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 * device_pixel_scale.0); + max_std_deviation = f32::max(max_std_deviation, shadow.blur_radius); } + 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, max_blur_range) + .inflate(max_blur_range * scale_factors.0, max_blur_range * scale_factors.1) .intersection(&unclipped) .unwrap(); @@ -4731,7 +4758,10 @@ impl PicturePrimitive { device_rect.size = RenderTask::adjusted_blur_source_size( device_rect.size, - DeviceSize::new(max_std_deviation, max_std_deviation), + DeviceSize::new( + max_std_deviation * scale_factors.0, + max_std_deviation * scale_factors.1 + ), ); if let Some(scale) = adjust_scale_for_max_surface_size( @@ -4775,14 +4805,12 @@ 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 { - // 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. + let blur_radius = clamp_blur_radius(shadow.blur_radius, scale_factors) * device_pixel_scale.0; blur_render_task_id = RenderTask::new_blur( DeviceSize::new( - 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, + blur_radius * scale_factors.0, + blur_radius * scale_factors.1, ), picture_task_id, frame_state.render_tasks, @@ -5602,33 +5630,6 @@ 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 @@ -5642,17 +5643,49 @@ 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, - if establishes_raster_root { - surface_spatial_node_index - } else { - parent_raster_node_index - }, + raster_spatial_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 { @@ -5786,7 +5819,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.inflation_factor); + surface.rect = raster_config.composite_mode.inflate_picture_rect(surface.rect, surface.scale_factors); // 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 ad1e24e61a0e..7653193b58f6 100644 --- a/gfx/wr/webrender/src/prim_store/mod.rs +++ b/gfx/wr/webrender/src/prim_store/mod.rs @@ -2384,7 +2384,8 @@ impl PrimitiveStore { surface.device_pixel_scale, frame_context.spatial_tree, ); - surface_rect = rc.composite_mode.inflate_picture_rect(surface_rect, surface.inflation_factor); + + surface_rect = rc.composite_mode.inflate_picture_rect(surface_rect, surface.scale_factors); 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 b39dd8e86a35..869f7590f256 100644 --- a/gfx/wr/webrender/src/scene_building.rs +++ b/gfx/wr/webrender/src/scene_building.rs @@ -2567,8 +2567,7 @@ 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 mut blur_filter = Filter::Blur(std_deviation); - blur_filter.sanitize(); + let blur_filter = Filter::Blur(std_deviation); let composite_mode = PictureCompositeMode::Filter(blur_filter); let composite_mode_key = Some(composite_mode.clone()).into(); @@ -3475,8 +3474,6 @@ 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 7863604ea461..3d54a3724759 100644 --- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -12,10 +12,6 @@ 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,12 +867,6 @@ 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 { @@ -905,12 +895,6 @@ 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 { @@ -968,9 +952,7 @@ 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(..) | @@ -978,6 +960,8 @@ 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 new file mode 100644 index 000000000000..cdc6c56a47b4 --- /dev/null +++ b/gfx/wr/wrench/reftests/filters/filter-blur-clamping-ref.yaml @@ -0,0 +1,18 @@ +# 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 new file mode 100644 index 000000000000..614aa8ee02af --- /dev/null +++ b/gfx/wr/wrench/reftests/filters/filter-blur-clamping.yaml @@ -0,0 +1,30 @@ +# 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 new file mode 100644 index 000000000000..6ffcde5f5b99 --- /dev/null +++ b/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping-ref.yaml @@ -0,0 +1,18 @@ +# 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 new file mode 100644 index 000000000000..1d7157a8e63a --- /dev/null +++ b/gfx/wr/wrench/reftests/filters/filter-drop-shadow-blur-clamping.yaml @@ -0,0 +1,30 @@ +# 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 65c699f8fa39..e46af9dfa404 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(999999.25) + transform: scale-y(100) items: - type: stacking-context bounds: [0, 0, 1000, 1000] - filters: drop-shadow([999999, 999999], 999999, [255, 0, 0, 1]) + filters: drop-shadow([0, 0], 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 7222c7b5c4e1..0853d8fbc76e 100644 --- a/gfx/wr/wrench/reftests/filters/reftest.list +++ b/gfx/wr/wrench/reftests/filters/reftest.list @@ -45,7 +45,9 @@ 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/reftests/svg/filters/reftest.list b/layout/reftests/svg/filters/reftest.list index 086557fcd63c..73ba280e88c0 100644 --- a/layout/reftests/svg/filters/reftest.list +++ b/layout/reftests/svg/filters/reftest.list @@ -43,7 +43,7 @@ fuzzy(0-1,0-6400) fuzzy-if(skiaContent,0-1,0-6404) fuzzy-if(webrender,178-178,30 fuzzy-if(webrender,0-2,0-304) == feGaussianBlur-2.svg feGaussianBlur-2-ref.svg # != feGaussianBlur-3.svg feGaussianBlur-3-ref.svg fuzzy-if(webrender,3-5,5500-8168) == feGaussianBlur-4.svg feGaussianBlur-4-ref.svg -== feGaussianBlur-5.svg feGaussianBlur-5-ref.svg +fuzzy-if(geckoview&&webrender,0-4,0-7) == feGaussianBlur-5.svg feGaussianBlur-5-ref.svg == feGaussianBlur-6.svg feGaussianBlur-6-ref.svg skip-if(d2d) == feGaussianBlur-cap-large-directional-radius-on-software.html feGaussianBlur-cap-large-directional-radius-on-software-ref.html