Implement support for the drop-shadow filter (#30439)

* Implement support for `drop-shadow`

* Clean up remnant from early attempts

* Fix misleading comments on GenericSimpleShadow
If Servo-specific `style` changes will need to be upstreamed anyway, I might as well fix a thing that had thrown me off!

* Revert "Fix misleading comments on GenericSimpleShadow"

This reverts commit cdc810b826ac082041adc212c24649ee3b86ca0a.

* Clean up an import

* Update test expectations

* Fix missing expectation on Layout 2013
This commit is contained in:
Ennui Langeweile 2023-10-04 08:32:45 -03:00 committed by GitHub
parent 8436002383
commit f7c340f881
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 51 additions and 355 deletions

View file

@ -62,7 +62,7 @@ use crate::display_list::items::{
PushTextShadowDisplayItem, StackingContext, StackingContextType, StickyFrameData,
TextOrientation, WebRenderImageInfo,
};
use crate::display_list::{border, gradient, ToLayout};
use crate::display_list::{border, gradient, FilterToLayout, ToLayout};
use crate::flow::{BaseFlow, Flow, FlowFlags};
use crate::flow_ref::FlowRef;
use crate::fragment::{
@ -1975,8 +1975,14 @@ impl Fragment {
.translate(-border_box_offset.to_vector());
// Create the filter pipeline.
let current_color = self.style().clone_color();
let effects = self.style().get_effects();
let mut filters: Vec<FilterOp> = effects.filter.0.iter().map(ToLayout::to_layout).collect();
let mut filters: Vec<FilterOp> = effects
.filter
.0
.iter()
.map(|filter| FilterToLayout::to_layout(filter, &current_color))
.collect();
if effects.opacity != 1.0 {
filters.push(FilterOp::Opacity(effects.opacity.into(), effects.opacity));
}

View file

@ -17,6 +17,11 @@ pub trait ToLayout {
fn to_layout(&self) -> Self::Type;
}
pub trait FilterToLayout {
type Type;
fn to_layout(&self, current_color: &RGBA) -> Self::Type;
}
impl ToLayout for BorderStyle {
type Type = wr::BorderStyle;
fn to_layout(&self) -> Self::Type {
@ -35,9 +40,9 @@ impl ToLayout for BorderStyle {
}
}
impl ToLayout for Filter {
impl FilterToLayout for Filter {
type Type = wr::FilterOp;
fn to_layout(&self) -> Self::Type {
fn to_layout(&self, current_color: &RGBA) -> Self::Type {
match *self {
Filter::Blur(radius) => wr::FilterOp::Blur(radius.px(), radius.px()),
Filter::Brightness(amount) => wr::FilterOp::Brightness(amount.0),
@ -48,8 +53,14 @@ impl ToLayout for Filter {
Filter::Opacity(amount) => wr::FilterOp::Opacity(amount.0.into(), amount.0),
Filter::Saturate(amount) => wr::FilterOp::Saturate(amount.0),
Filter::Sepia(amount) => wr::FilterOp::Sepia(amount.0),
// Statically check that DropShadow is impossible.
Filter::DropShadow(ref shadow) => match *shadow {},
Filter::DropShadow(ref shadow) => wr::FilterOp::DropShadow(wr::Shadow {
blur_radius: shadow.blur.px(),
offset: wr::units::LayoutVector2D::new(
shadow.horizontal.px(),
shadow.vertical.px(),
),
color: shadow.color.clone().into_rgba(*current_color).to_layout(),
}),
// Statically check that Url is impossible.
Filter::Url(ref url) => match *url {},
}

View file

@ -6,7 +6,7 @@ pub use self::builder::{
BorderPaintingMode, DisplayListBuildState, IndexableText, StackingContextCollectionFlags,
StackingContextCollectionState,
};
pub use self::conversions::ToLayout;
pub use self::conversions::{FilterToLayout, ToLayout};
mod background;
mod border;

View file

@ -6,7 +6,8 @@ use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
use style::computed_values::text_decoration_style::T as ComputedTextDecorationStyle;
use style::computed_values::transform_style::T as ComputedTransformStyle;
use style::values::computed::{Filter as ComputedFilter, Length};
use webrender_api::{units, FilterOp, LineStyle, MixBlendMode, TransformStyle};
use style::values::RGBA;
use webrender_api::{units, FilterOp, LineStyle, MixBlendMode, Shadow, TransformStyle};
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize};
@ -15,9 +16,14 @@ pub trait ToWebRender {
fn to_webrender(&self) -> Self::Type;
}
impl ToWebRender for ComputedFilter {
pub trait FilterToWebRender {
type Type;
fn to_webrender(&self, current_color: &RGBA) -> Self::Type;
}
impl FilterToWebRender for ComputedFilter {
type Type = FilterOp;
fn to_webrender(&self) -> Self::Type {
fn to_webrender(&self, current_color: &RGBA) -> Self::Type {
match *self {
ComputedFilter::Blur(radius) => FilterOp::Blur(radius.px(), radius.px()),
ComputedFilter::Brightness(amount) => FilterOp::Brightness(amount.0),
@ -28,13 +34,17 @@ impl ToWebRender for ComputedFilter {
ComputedFilter::Opacity(amount) => FilterOp::Opacity(amount.0.into(), amount.0),
ComputedFilter::Saturate(amount) => FilterOp::Saturate(amount.0),
ComputedFilter::Sepia(amount) => FilterOp::Sepia(amount.0),
// Statically check that DropShadow is impossible.
ComputedFilter::DropShadow(ref shadow) => match *shadow {},
ComputedFilter::DropShadow(ref shadow) => FilterOp::DropShadow(Shadow {
blur_radius: shadow.blur.px(),
offset: units::LayoutVector2D::new(shadow.horizontal.px(), shadow.vertical.px()),
color: super::rgba(shadow.color.clone().into_rgba(*current_color)),
}),
// Statically check that Url is impossible.
ComputedFilter::Url(ref url) => match *url {},
}
}
}
impl ToWebRender for ComputedMixBlendMode {
type Type = MixBlendMode;
fn to_webrender(&self) -> Self::Type {

View file

@ -23,7 +23,7 @@ use webrender_api::ScrollSensitivity;
use super::DisplayList;
use crate::cell::ArcRefCell;
use crate::display_list::conversions::ToWebRender;
use crate::display_list::conversions::{FilterToWebRender, ToWebRender};
use crate::display_list::DisplayListBuilder;
use crate::fragment_tree::{
AnonymousFragment, BoxFragment, ContainingBlockManager, Fragment, FragmentTree,
@ -341,11 +341,12 @@ impl StackingContext {
}
// Create the filter pipeline.
let current_color = style.clone_color();
let mut filters: Vec<wr::FilterOp> = effects
.filter
.0
.iter()
.map(ToWebRender::to_webrender)
.map(|filter| FilterToWebRender::to_webrender(filter, &current_color))
.collect();
if effects.opacity != 1.0 {
filters.push(wr::FilterOp::Opacity(

View file

@ -749,7 +749,7 @@ impl Animate for AnimatedFilter {
) -> Result<Self, ()> {
use crate::values::animated::animate_multiplicative_factor;
match (self, other) {
% for func in ['Blur', 'Grayscale', 'HueRotate', 'Invert', 'Sepia']:
% for func in ['Blur', 'DropShadow', 'Grayscale', 'HueRotate', 'Invert', 'Sepia']:
(&Filter::${func}(ref this), &Filter::${func}(ref other)) => {
Ok(Filter::${func}(this.animate(other, procedure)?))
},
@ -759,11 +759,6 @@ impl Animate for AnimatedFilter {
Ok(Filter::${func}(animate_multiplicative_factor(this, other, procedure)?))
},
% endfor
% if engine == "gecko":
(&Filter::DropShadow(ref this), &Filter::DropShadow(ref other)) => {
Ok(Filter::DropShadow(this.animate(other, procedure)?))
},
% endif
_ => Err(()),
}
}
@ -773,15 +768,12 @@ impl Animate for AnimatedFilter {
impl ToAnimatedZero for AnimatedFilter {
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
% for func in ['Blur', 'Grayscale', 'HueRotate', 'Invert', 'Sepia']:
% for func in ['Blur', 'DropShadow', 'Grayscale', 'HueRotate', 'Invert', 'Sepia']:
Filter::${func}(ref this) => Ok(Filter::${func}(this.to_animated_zero()?)),
% endfor
% for func in ['Brightness', 'Contrast', 'Opacity', 'Saturate']:
Filter::${func}(_) => Ok(Filter::${func}(1.)),
% endfor
% if engine == "gecko":
Filter::DropShadow(ref this) => Ok(Filter::DropShadow(this.to_animated_zero()?)),
% endif
_ => Err(()),
}
}

View file

@ -24,4 +24,4 @@ pub type AnimatedFilter =
/// An animated value for a single `filter`.
#[cfg(not(feature = "gecko"))]
pub type AnimatedFilter = GenericFilter<Angle, Number, Number, Length, Impossible, Impossible>;
pub type AnimatedFilter = GenericFilter<Angle, Number, Number, Length, AnimatedSimpleShadow, Impossible>;

View file

@ -36,7 +36,7 @@ pub type Filter = GenericFilter<
NonNegativeNumber,
ZeroToOneNumber,
NonNegativeLength,
Impossible,
SimpleShadow,
Impossible,
>;

View file

@ -47,7 +47,7 @@ pub type SpecifiedFilter = GenericFilter<
NonNegativeFactor,
ZeroToOneFactor,
NonNegativeLength,
Impossible,
SimpleShadow,
Impossible,
>;