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)
This commit is contained in:
shindli 2020-03-11 10:36:47 +02:00
Родитель 0819017624
Коммит 0b1a68a2ad
14 изменённых файлов: 104 добавлений и 200 удалений

Просмотреть файл

@ -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.

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 |

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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 =

Просмотреть файл

@ -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(..) => {}
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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]

Просмотреть файл

@ -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

Просмотреть файл

@ -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<const StyleFilter> 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: {