use crate::render::background::get_cyclic;
use super::ElementCx;
use super::background::ImageLayerStyles;
use anyrender::PaintScene;
use peniko::{BlendMode, Compose, Mix};
use style::properties::generated::longhands::mask_composite::single_value::computed_value::T as StyloMaskComposite;
use style::values::generics::image::GenericImage;
#[cfg(feature = "tracing")]
use tracing::warn;
const ALMOST_OPAQUE: f32 = 1.0 - f32::EPSILON;
impl ElementCx<'_, '_> {
pub(super) fn has_css_mask(&self) -> bool {
self.style
.get_svg()
.mask_image
.0
.iter()
.any(|image| !matches!(image, GenericImage::None))
}
pub(super) fn maybe_push_css_mask_layer(&self, scene: &mut impl PaintScene) -> bool {
if !self.has_css_mask() {
return false;
}
scene.push_layer(
Mix::Normal,
ALMOST_OPAQUE,
self.transform,
&self.frame.border_box_path(),
None,
None,
);
true
}
pub(super) fn maybe_pop_css_mask_layer(&self, scene: &mut impl PaintScene, layer_pushed: bool) {
if !layer_pushed {
return;
}
scene.push_layer(
BlendMode::new(Mix::Normal, Compose::DestIn),
1.0,
self.transform,
&self.frame.border_box_path(),
None,
None,
);
self.draw_css_mask(scene);
scene.pop_layer(); scene.pop_layer(); }
fn draw_css_mask(&self, scene: &mut impl PaintScene) {
let svg_styles = self.style.get_svg();
let image_data = &self.element.mask_images;
let layer_count = svg_styles.mask_image.0.len();
for idx in (0..layer_count).rev() {
let layer = ImageLayerStyles::from_svg(svg_styles, image_data, idx);
let mask_clip_path = self.box_path(layer.clip);
#[cfg(feature = "tracing")]
{
use style::properties::generated::longhands::mask_mode::single_value::computed_value::T as StyloMaskMode;
let mask_mode = &svg_styles.mask_mode.0;
if matches!(get_cyclic(&mask_mode, idx), StyloMaskMode::Luminance) {
warn!("mask-mode: luminance is not supported (falling back to alpha)");
}
}
let compose = if idx == layer_count - 1 {
Compose::SrcOver
} else {
let composite_list = &svg_styles.mask_composite.0;
match get_cyclic(composite_list, idx) {
StyloMaskComposite::Add => Compose::SrcOver,
StyloMaskComposite::Subtract => Compose::SrcOut,
StyloMaskComposite::Intersect => Compose::SrcIn,
StyloMaskComposite::Exclude => Compose::Xor,
}
};
scene.push_layer(
BlendMode::new(Mix::Normal, compose),
1.0,
self.transform,
&mask_clip_path,
None,
None,
);
self.draw_image_layer(scene, &layer);
scene.pop_layer();
}
}
}