// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 /*! This module contains a cache helper for caching box shadow textures. */ use std::{cell::RefCell, collections::BTreeMap}; use crate::items::ItemRc; use crate::lengths::RectLengths; use crate::{ lengths::{PhysicalPx, ScaleFactor}, Color, }; /// Struct to store options affecting the rendering of a box shadow #[derive(Clone, PartialEq, Debug, Default)] pub struct BoxShadowOptions { /// The width of the box shadow texture in physical pixels. pub width: euclid::Length, /// The height of the box shadow texture in physical pixels. pub height: euclid::Length, /// The color for the box shadow. pub color: Color, /// The blur to apply to the box shadow in pixels. pub blur: euclid::Length, /// The radius of the box shadow. pub radius: euclid::Length, } impl Eq for BoxShadowOptions {} impl Ord for BoxShadowOptions { fn cmp(&self, other: &Self) -> std::cmp::Ordering { if (other.width, other.height, other.color, other.blur, other.radius) < (self.width, self.height, self.color, self.blur, self.radius) { std::cmp::Ordering::Less } else if (self.width, self.height, self.color, self.blur, self.radius) < (other.width, other.height, other.color, other.blur, other.radius) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal } } } impl PartialOrd for BoxShadowOptions { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl BoxShadowOptions { /// Extracts the rendering specific properties from the BoxShadow item and scales the logical /// coordinates to physical pixels used in the BoxShadowOptions. Returns None if for example the /// alpha on the box shadow would imply that no shadow is to be rendered. pub fn new( item_rc: &ItemRc, box_shadow: std::pin::Pin<&crate::items::BoxShadow>, scale_factor: ScaleFactor, ) -> Option { let color = box_shadow.color(); if color.alpha() == 0 { return None; } let geometry = item_rc.geometry(); let width = geometry.width_length() * scale_factor; let height = geometry.height_length() * scale_factor; if width.get() < 1. || height.get() < 1. { return None; } Some(Self { width, height, color, blur: box_shadow.blur() * scale_factor, // This effectively becomes the blur radius, so scale to physical pixels radius: box_shadow.border_radius() * scale_factor, }) } } /// Cache to hold box textures for given box shadow options. pub struct BoxShadowCache(RefCell>); impl Default for BoxShadowCache { fn default() -> Self { Self(Default::default()) } } impl BoxShadowCache { /// Look up a box shadow texture for a given box shadow item, or create a new one if needed. pub fn get_box_shadow( &self, item_rc: &ItemRc, item_cache: &crate::item_rendering::ItemCache>, box_shadow: std::pin::Pin<&crate::items::BoxShadow>, scale_factor: ScaleFactor, shadow_render_fn: impl FnOnce(&BoxShadowOptions) -> ImageType, ) -> Option { item_cache.get_or_update_cache_entry(item_rc, || { let shadow_options = BoxShadowOptions::new(item_rc, box_shadow, scale_factor)?; self.0 .borrow_mut() .entry(shadow_options.clone()) .or_insert_with(|| shadow_render_fn(&shadow_options)) .clone() .into() }) } }