Skip to main content

vizia_core/style/
mod.rs

1//! Styling determines the appearance of a view.
2//!
3//! # Styling Views
4//! Vizia provides two ways to style views:
5//! - Inline
6//! - Shared
7//!
8//! ## Inline Styling
9//! Inline styling refers to setting the style and layout properties of a view using view [modifiers](crate::modifiers).
10//! ```
11//! # use vizia_core::prelude::*;
12//! # let cx = &mut Context::default();
13//! Element::new(cx).background_color(Color::red());
14//! ```
15//! Properties set inline affect only the modified view and override any shared styling for the same property.
16//!
17//! ## Shared Styling
18//! Shared styling refers to setting the style and layout properties using css rules.
19//! ```
20//! # use vizia_core::prelude::*;
21//! # let cx = &mut Context::default();
22//! Element::new(cx).class("foo");
23//! ```
24//! ```css
25//! .foo {
26//!     background-color: red;
27//! }
28//! ```
29//! Rules defined in css can apply to many views but are overridden by inline properties on a view.
30//!
31//! ### Adding Stylesheets
32//! To add a css string to an application, use [`add_theme()`](crate::context::Context::add_theme()) on [`Context`].
33//! This can be used with the `include_str!()` macro to embed an external stylesheet file into the application binary when compiled.
34//! Alternatively a constant string literal can be used to embed the CSS in the application.
35//!
36//! ```
37//! # use vizia_core::prelude::*;
38//! # let cx = &mut Context::default();
39//!
40//! const STYLE: &str = r#"
41//!     .foo {
42//!         background-color: red;
43//!     }
44//! "#;
45//!
46//! cx.add_stylesheet(STYLE);
47//!
48//! Element::new(cx).class("foo");
49//! ```
50//!
51//! To add an external css stylesheet which is read from a file at runtime, use [`add_stylesheet()`](crate::context::Context::add_stylesheet()) on [`Context`].
52//! Stylesheets added this way can be hot-reloaded by pressing the F5 key in the application window.
53//!
54//! ```
55//! # use vizia_core::prelude::*;
56//! # let cx = &mut Context::default();
57//!
58//! cx.add_stylesheet("path/to/stylesheet.css");
59//!
60//! Element::new(cx).class("foo");
61//! ```
62
63use accesskit::SortDirection;
64use hashbrown::{HashMap, HashSet};
65use indexmap::IndexMap;
66use log::warn;
67use std::fmt::Debug;
68use std::hash::{DefaultHasher, Hash, Hasher};
69use std::ops::Range;
70use vizia_style::selectors::parser::{AncestorHashes, Selector};
71
72use crate::prelude::*;
73use crate::storage::animatable_var_set::AnimatableVarSet;
74
75pub use vizia_style::{
76    Alignment, Angle, AspectRatio, BackgroundImage, BackgroundRepeat, BackgroundSize,
77    BorderStyleKeyword, ClipPath, Color, CssRule, CursorIcon, Direction, Display, Filter,
78    FontFamily, FontSize, FontSizeKeyword, FontSlant, FontVariation, FontWeight, FontWeightKeyword,
79    FontWidth, GenericFontFamily, Gradient, HorizontalPosition, HorizontalPositionKeyword,
80    LayoutWrap, Length, LengthOrPercentage, LengthValue, LetterSpacing, LineClamp, LineDirection,
81    LineHeight, LinearGradient, Matrix, Opacity, Overflow, PointerEvents, Position, PositionType,
82    RGBA, Scale, Shadow, TextAlign, TextDecorationLine, TextDecorationStyle, TextOverflow,
83    TextStroke, TextStrokeStyle, Transform, Transition, Translate, VerticalPosition,
84    VerticalPositionKeyword, Visibility,
85};
86
87use cssparser::Token as CssToken;
88use vizia_style::{
89    BlendMode, EasingFunction, KeyframeSelector, ParserOptions, Property, Selectors, StyleSheet,
90    TokenList, TokenOrValue, Variable,
91};
92
93mod rule;
94pub(crate) use rule::Rule;
95
96mod pseudoclass;
97pub(crate) use pseudoclass::*;
98
99mod transform;
100pub(crate) use transform::*;
101
102use crate::animation::{AnimationState, Interpolator, Keyframe, TimingFunction};
103use crate::storage::animatable_set::AnimatableSet;
104use crate::storage::style_set::StyleSet;
105use bitflags::bitflags;
106use vizia_id::IdManager;
107use vizia_storage::SparseSet;
108
109bitflags! {
110    /// Describes the capabilities of a view with respect to user interaction.
111    #[derive(Debug, Clone, Copy)]
112    pub(crate) struct Abilities: u8 {
113        // Whether a view will be included in hit tests and receive mouse input events.
114        const HOVERABLE = 1 << 0;
115        // Whether a view can be focused to receive keyboard events.
116        const FOCUSABLE = 1 << 1;
117        // Whether a view can be checked.
118        const CHECKABLE = 1 << 2;
119        // Whether a view can be focused via keyboard navigation.
120        const NAVIGABLE = 1 << 3;
121        // Whether a view can be dragged during a drag and drop.
122        const DRAGGABLE = 1 << 4;
123    }
124}
125
126impl Default for Abilities {
127    fn default() -> Abilities {
128        Abilities::HOVERABLE
129    }
130}
131
132bitflags! {
133    pub(crate) struct SystemFlags: u8 {
134        const RELAYOUT = 1;
135        const RESTYLE = 1 << 1;
136        const REFLOW = 1 << 2;
137        const REDRAW = 1 << 3;
138        const RETRANSFORM = 1 << 4;
139        const RECLIP = 1 << 5;
140        const REACCESS = 1 << 6;
141    }
142}
143
144impl Default for SystemFlags {
145    fn default() -> Self {
146        SystemFlags::all()
147    }
148}
149
150/// An enum which represents an image or a gradient.
151#[derive(Debug, Clone, PartialEq)]
152pub enum ImageOrGradient {
153    /// Represents an image by name.
154    Image(String),
155    /// A gradient.
156    Gradient(Gradient),
157}
158
159/// A font-family.
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub enum FamilyOwned {
162    /// A generic font-family.
163    Generic(GenericFontFamily),
164    /// A named front-family.
165    Named(String),
166}
167
168impl AsRef<str> for FamilyOwned {
169    fn as_ref(&self) -> &str {
170        match self {
171            FamilyOwned::Generic(generic) => match generic {
172                GenericFontFamily::Serif => "serif",
173                GenericFontFamily::SansSerif => "sans-serif",
174                GenericFontFamily::Cursive => todo!(),
175                GenericFontFamily::Fantasy => todo!(),
176                GenericFontFamily::Monospace => "Cascadia Mono",
177            },
178            FamilyOwned::Named(family) => family.as_str(),
179        }
180    }
181}
182
183pub(crate) struct StyleRule {
184    pub(crate) selector: Selector<Selectors>,
185    /// The ancestor hashes associated with the selector.
186    pub(crate) hashes: AncestorHashes,
187}
188
189impl StyleRule {
190    pub(crate) fn new(selector: Selector<Selectors>) -> Self {
191        let hashes = AncestorHashes::new(&selector, vizia_style::QuirksMode::NoQuirks);
192        Self { selector, hashes }
193    }
194}
195
196/// Stores the style properties of all entities in the application.
197#[derive(Default)]
198pub struct Style {
199    pub(crate) rule_manager: IdManager<Rule>,
200
201    // Creates and destroys animation ids
202    pub(crate) animation_manager: IdManager<Animation>,
203    pub(crate) animations: HashMap<String, Animation>,
204    // List of animations to be started on the next frame
205    pub(crate) pending_animations: Vec<(Entity, Animation, Duration, Duration)>,
206
207    // List of rules
208    pub(crate) rules: IndexMap<Rule, StyleRule>,
209
210    pub(crate) default_font: Vec<FamilyOwned>,
211
212    // CSS Selector Properties
213    pub(crate) element: SparseSet<u32>,
214    pub(crate) ids: SparseSet<String>,
215    pub(crate) classes: SparseSet<HashSet<String>>,
216    pub(crate) pseudo_classes: SparseSet<PseudoClassFlags>,
217    pub(crate) disabled: StyleSet<bool>,
218    pub(crate) abilities: SparseSet<Abilities>,
219
220    // Accessibility Properties
221    pub(crate) name: StyleSet<String>,
222    pub(crate) role: SparseSet<Role>,
223    pub(crate) live: SparseSet<Live>,
224    pub(crate) labelled_by: SparseSet<String>,
225    pub(crate) described_by: SparseSet<String>,
226    pub(crate) controls: SparseSet<String>,
227    pub(crate) active_descendant: SparseSet<String>,
228    pub(crate) expanded: SparseSet<bool>,
229    pub(crate) selected: SparseSet<bool>,
230    pub(crate) multiselectable: SparseSet<bool>,
231    pub(crate) sort_direction: SparseSet<SortDirection>,
232    pub(crate) level: SparseSet<usize>,
233    pub(crate) size_of_set: SparseSet<usize>,
234    pub(crate) position_in_set: SparseSet<usize>,
235    pub(crate) hidden: SparseSet<bool>,
236    pub(crate) orientation: SparseSet<Orientation>,
237    pub(crate) text_value: SparseSet<String>,
238    pub(crate) numeric_value: SparseSet<f64>,
239
240    // Visibility
241    pub(crate) visibility: StyleSet<Visibility>,
242
243    // Opacity
244    pub(crate) opacity: AnimatableVarSet<Opacity>,
245
246    // Z Order
247    pub(crate) z_index: StyleSet<i32>,
248
249    // Controls whether an entity should ignore ancestor clipping during drawing.
250    pub(crate) ignore_clipping: StyleSet<bool>,
251
252    // Clipping
253    pub(crate) clip_path: AnimatableSet<ClipPath>,
254
255    // Overflow
256    pub(crate) overflowx: StyleSet<Overflow>,
257    pub(crate) overflowy: StyleSet<Overflow>,
258
259    // Filters
260    pub(crate) filter: AnimatableSet<Filter>,
261    pub(crate) backdrop_filter: AnimatableSet<Filter>,
262
263    pub(crate) blend_mode: StyleSet<BlendMode>,
264
265    // Transform
266    pub(crate) transform: AnimatableSet<Vec<Transform>>,
267    pub(crate) transform_origin: AnimatableSet<Translate>,
268    pub(crate) translate: AnimatableSet<Translate>,
269    pub(crate) rotate: AnimatableSet<Angle>,
270    pub(crate) scale: AnimatableSet<Scale>,
271
272    // Border widths (per side)
273    pub(crate) border_top_width: AnimatableVarSet<LengthOrPercentage>,
274    pub(crate) border_right_width: AnimatableVarSet<LengthOrPercentage>,
275    pub(crate) border_bottom_width: AnimatableVarSet<LengthOrPercentage>,
276    pub(crate) border_left_width: AnimatableVarSet<LengthOrPercentage>,
277
278    // Border colors (per side)
279    pub(crate) border_top_color: AnimatableVarSet<Color>,
280    pub(crate) border_right_color: AnimatableVarSet<Color>,
281    pub(crate) border_bottom_color: AnimatableVarSet<Color>,
282    pub(crate) border_left_color: AnimatableVarSet<Color>,
283
284    // Border styles (per side)
285    pub(crate) border_top_style: StyleSet<BorderStyleKeyword>,
286    pub(crate) border_right_style: StyleSet<BorderStyleKeyword>,
287    pub(crate) border_bottom_style: StyleSet<BorderStyleKeyword>,
288    pub(crate) border_left_style: StyleSet<BorderStyleKeyword>,
289
290    // Corner Radius
291    pub(crate) corner_top_left_radius: AnimatableVarSet<LengthOrPercentage>,
292    pub(crate) corner_top_right_radius: AnimatableVarSet<LengthOrPercentage>,
293    pub(crate) corner_bottom_left_radius: AnimatableVarSet<LengthOrPercentage>,
294    pub(crate) corner_bottom_right_radius: AnimatableVarSet<LengthOrPercentage>,
295
296    // Outline
297    pub(crate) outline_width: AnimatableVarSet<LengthOrPercentage>,
298    pub(crate) outline_color: AnimatableVarSet<Color>,
299    pub(crate) outline_offset: AnimatableVarSet<LengthOrPercentage>,
300
301    // Background
302    pub(crate) background_color: AnimatableVarSet<Color>,
303    pub(crate) background_image: AnimatableSet<Vec<ImageOrGradient>>,
304    pub(crate) background_position: AnimatableSet<Vec<Position>>,
305    pub(crate) background_repeat: AnimatableSet<Vec<BackgroundRepeat>>,
306    pub(crate) background_size: AnimatableSet<Vec<BackgroundSize>>,
307
308    // Shadow
309    pub(crate) shadow: AnimatableVarSet<Vec<Shadow>>,
310
311    // Text
312    pub(crate) text: SparseSet<String>,
313    pub(crate) text_wrap: StyleSet<bool>,
314    pub(crate) text_overflow: StyleSet<TextOverflow>,
315    pub(crate) letter_spacing: AnimatableVarSet<LetterSpacing>,
316    pub(crate) line_height: AnimatableVarSet<LineHeight>,
317    pub(crate) line_clamp: StyleSet<LineClamp>,
318    pub(crate) text_align: StyleSet<TextAlign>,
319    pub(crate) text_decoration_line: StyleSet<TextDecorationLine>,
320    pub(crate) text_decoration_style: StyleSet<TextDecorationStyle>,
321    pub(crate) text_decoration_color: AnimatableVarSet<Color>,
322    pub(crate) text_stroke_width: StyleSet<Length>,
323    pub(crate) text_stroke_style: StyleSet<TextStrokeStyle>,
324    pub(crate) font_family: StyleSet<Vec<FamilyOwned>>,
325    pub(crate) font_color: AnimatableVarSet<Color>,
326    pub(crate) font_size: AnimatableVarSet<FontSize>,
327    pub(crate) font_weight: StyleSet<FontWeight>,
328    pub(crate) font_slant: StyleSet<FontSlant>,
329    pub(crate) font_width: StyleSet<FontWidth>,
330    pub(crate) font_variation_settings: StyleSet<Vec<FontVariation>>,
331    pub(crate) caret_color: AnimatableVarSet<Color>,
332    pub(crate) selection_color: AnimatableVarSet<Color>,
333
334    pub(crate) fill: AnimatableVarSet<Color>,
335
336    // cursor Icon
337    pub(crate) cursor: StyleSet<CursorIcon>,
338
339    pub(crate) pointer_events: StyleSet<PointerEvents>,
340
341    // LAYOUT
342
343    // Display
344    pub(crate) display: AnimatableSet<Display>,
345
346    // Layout Type
347    pub(crate) layout_type: StyleSet<LayoutType>,
348
349    // Position
350    pub(crate) position_type: StyleSet<PositionType>,
351
352    pub(crate) alignment: StyleSet<Alignment>,
353    pub(crate) direction: StyleSet<Direction>,
354    pub(crate) wrap: StyleSet<LayoutWrap>,
355
356    // Grid
357    pub(crate) grid_columns: StyleSet<Vec<Units>>,
358    pub(crate) grid_rows: StyleSet<Vec<Units>>,
359
360    pub(crate) column_start: StyleSet<usize>,
361    pub(crate) column_span: StyleSet<usize>,
362    pub(crate) row_start: StyleSet<usize>,
363    pub(crate) row_span: StyleSet<usize>,
364
365    // Spacing
366    pub(crate) left: AnimatableVarSet<Units>,
367    pub(crate) right: AnimatableVarSet<Units>,
368    pub(crate) top: AnimatableVarSet<Units>,
369    pub(crate) bottom: AnimatableVarSet<Units>,
370
371    // Padding
372    pub(crate) padding_left: AnimatableVarSet<Units>,
373    pub(crate) padding_right: AnimatableVarSet<Units>,
374    pub(crate) padding_top: AnimatableVarSet<Units>,
375    pub(crate) padding_bottom: AnimatableVarSet<Units>,
376    pub(crate) vertical_gap: AnimatableVarSet<Units>,
377    pub(crate) horizontal_gap: AnimatableVarSet<Units>,
378
379    // Size
380    pub(crate) width: AnimatableVarSet<Units>,
381    pub(crate) height: AnimatableVarSet<Units>,
382    pub(crate) aspect_ratio: StyleSet<AspectRatio>,
383
384    // Size Constraints
385    pub(crate) min_width: AnimatableVarSet<Units>,
386    pub(crate) max_width: AnimatableVarSet<Units>,
387    pub(crate) min_height: AnimatableVarSet<Units>,
388    pub(crate) max_height: AnimatableVarSet<Units>,
389
390    // Gap Constraints
391    pub(crate) min_horizontal_gap: AnimatableVarSet<Units>,
392    pub(crate) max_horizontal_gap: AnimatableVarSet<Units>,
393    pub(crate) min_vertical_gap: AnimatableVarSet<Units>,
394    pub(crate) max_vertical_gap: AnimatableVarSet<Units>,
395
396    pub(crate) system_flags: SystemFlags,
397
398    /// Whether the layout debug overlay is enabled. Mirrored from the [`Environment`] model so
399    /// that the layout and draw systems can read it directly.
400    pub(crate) debug_layout: bool,
401
402    pub(crate) restyle: HashSet<Entity>,
403    /// Set of entities which need (incremental) relayout. Marking the root signals a full
404    /// relayout of the whole tree.
405    pub(crate) relayout: HashSet<Entity>,
406    /// Debug overlay: set of entities which underwent layout in the last relayout pass. Only
407    /// populated when the layout debug overlay is enabled (see `debug_layout`).
408    pub(crate) laid_out: HashSet<Entity>,
409    pub(crate) text_construction: HashSet<Entity>,
410    pub(crate) text_layout: HashSet<Entity>,
411    pub(crate) reaccess: HashSet<Entity>,
412    pub(crate) retransform: HashSet<Entity>,
413    pub(crate) reclip: HashSet<Entity>,
414
415    pub(crate) text_range: SparseSet<Range<usize>>,
416    pub(crate) text_span: SparseSet<bool>,
417
418    /// This includes both the system's HiDPI scaling factor as well as `cx.user_scale_factor`.
419    pub(crate) dpi_factor: f64,
420
421    pub(crate) custom_color_props: HashMap<u64, AnimatableVarSet<Color>>,
422    pub(crate) custom_length_props: HashMap<u64, AnimatableVarSet<LengthOrPercentage>>,
423    pub(crate) custom_font_size_props: HashMap<u64, AnimatableVarSet<FontSize>>,
424    pub(crate) custom_letter_spacing_props: HashMap<u64, AnimatableVarSet<LetterSpacing>>,
425    pub(crate) custom_line_height_props: HashMap<u64, AnimatableVarSet<LineHeight>>,
426    pub(crate) custom_units_props: HashMap<u64, AnimatableVarSet<Units>>,
427    pub(crate) custom_opacity_props: HashMap<u64, AnimatableVarSet<Opacity>>,
428    pub(crate) custom_shadow_props: HashMap<u64, AnimatableVarSet<Vec<Shadow>>>,
429}
430
431impl Style {
432    /// Returns the scale factor of the application.
433    pub fn scale_factor(&self) -> f32 {
434        self.dpi_factor as f32
435    }
436
437    /// Function to convert logical points to physical pixels.
438    pub fn logical_to_physical(&self, logical: f32) -> f32 {
439        (logical * self.dpi_factor as f32).round()
440    }
441
442    /// Function to convert physical pixels to logical points.
443    pub fn physical_to_logical(&self, physical: f32) -> f32 {
444        physical / self.dpi_factor as f32
445    }
446
447    pub(crate) fn remove_rules(&mut self) {
448        self.rule_manager.reset();
449        self.rules.clear();
450    }
451
452    pub(crate) fn get_animation(&self, name: &str) -> Option<&Animation> {
453        self.animations.get(name)
454    }
455
456    pub(crate) fn add_keyframe(
457        &mut self,
458        animation_id: Animation,
459        time: f32,
460        properties: &[Property],
461    ) {
462        fn insert_keyframe<T: 'static + Interpolator + Debug + Clone + PartialEq + Default>(
463            storage: &mut AnimatableSet<T>,
464            animation_id: Animation,
465            time: f32,
466            value: T,
467        ) {
468            let keyframe = Keyframe { time, value, timing_function: TimingFunction::linear() };
469
470            if let Some(anim_state) = storage.get_animation_mut(animation_id) {
471                anim_state.keyframes.push(keyframe)
472            } else {
473                let anim_state = AnimationState::new(animation_id).with_keyframe(keyframe);
474                storage.insert_animation(animation_id, anim_state);
475            }
476        }
477
478        fn insert_keyframe2<T: 'static + Interpolator + Debug + Clone + PartialEq + Default>(
479            storage: &mut AnimatableVarSet<T>,
480            animation_id: Animation,
481            time: f32,
482            value: T,
483        ) {
484            let keyframe = Keyframe { time, value, timing_function: TimingFunction::linear() };
485
486            if let Some(anim_state) = storage.get_animation_mut(animation_id) {
487                anim_state.keyframes.push(keyframe)
488            } else {
489                let anim_state = AnimationState::new(animation_id).with_keyframe(keyframe);
490                storage.insert_animation(animation_id, anim_state);
491            }
492        }
493
494        for property in properties.iter() {
495            match property {
496                // DISPLAY
497                Property::Display(value) => {
498                    insert_keyframe(&mut self.display, animation_id, time, *value);
499                }
500
501                Property::Opacity(value) => {
502                    insert_keyframe2(&mut self.opacity, animation_id, time, *value);
503                }
504
505                Property::ClipPath(value) => {
506                    insert_keyframe(&mut self.clip_path, animation_id, time, value.clone());
507                }
508
509                // TRANSFORM
510                Property::Transform(value) => {
511                    insert_keyframe(&mut self.transform, animation_id, time, value.clone());
512                }
513
514                Property::TransformOrigin(transform_origin) => {
515                    let x = transform_origin.x.to_length_or_percentage();
516                    let y = transform_origin.y.to_length_or_percentage();
517                    let value = Translate { x, y };
518                    insert_keyframe(&mut self.transform_origin, animation_id, time, value);
519                }
520
521                Property::Translate(value) => {
522                    insert_keyframe(&mut self.translate, animation_id, time, value.clone());
523                }
524
525                Property::Rotate(value) => {
526                    insert_keyframe(&mut self.rotate, animation_id, time, *value);
527                }
528
529                Property::Scale(value) => {
530                    insert_keyframe(&mut self.scale, animation_id, time, *value);
531                }
532
533                // BORDER
534                Property::Border(value) => {
535                    if let Some(color) = value.color {
536                        insert_keyframe2(&mut self.border_top_color, animation_id, time, color);
537                        insert_keyframe2(&mut self.border_right_color, animation_id, time, color);
538                        insert_keyframe2(&mut self.border_bottom_color, animation_id, time, color);
539                        insert_keyframe2(&mut self.border_left_color, animation_id, time, color);
540                    }
541                    if let Some(width) = value.width.clone() {
542                        let w: LengthOrPercentage = width.into();
543                        insert_keyframe2(&mut self.border_top_width, animation_id, time, w.clone());
544                        insert_keyframe2(
545                            &mut self.border_right_width,
546                            animation_id,
547                            time,
548                            w.clone(),
549                        );
550                        insert_keyframe2(
551                            &mut self.border_bottom_width,
552                            animation_id,
553                            time,
554                            w.clone(),
555                        );
556                        insert_keyframe2(&mut self.border_left_width, animation_id, time, w);
557                    }
558                }
559
560                Property::BorderTop(value) => {
561                    if let Some(color) = value.color {
562                        insert_keyframe2(&mut self.border_top_color, animation_id, time, color);
563                    }
564                    if let Some(width) = value.width.clone() {
565                        insert_keyframe2(
566                            &mut self.border_top_width,
567                            animation_id,
568                            time,
569                            width.into(),
570                        );
571                    }
572                }
573
574                Property::BorderRight(value) => {
575                    if let Some(color) = value.color {
576                        insert_keyframe2(&mut self.border_right_color, animation_id, time, color);
577                    }
578                    if let Some(width) = value.width.clone() {
579                        insert_keyframe2(
580                            &mut self.border_right_width,
581                            animation_id,
582                            time,
583                            width.into(),
584                        );
585                    }
586                }
587
588                Property::BorderBottom(value) => {
589                    if let Some(color) = value.color {
590                        insert_keyframe2(&mut self.border_bottom_color, animation_id, time, color);
591                    }
592                    if let Some(width) = value.width.clone() {
593                        insert_keyframe2(
594                            &mut self.border_bottom_width,
595                            animation_id,
596                            time,
597                            width.into(),
598                        );
599                    }
600                }
601
602                Property::BorderLeft(value) => {
603                    if let Some(color) = value.color {
604                        insert_keyframe2(&mut self.border_left_color, animation_id, time, color);
605                    }
606                    if let Some(width) = value.width.clone() {
607                        insert_keyframe2(
608                            &mut self.border_left_width,
609                            animation_id,
610                            time,
611                            width.into(),
612                        );
613                    }
614                }
615
616                Property::BorderWidth(value) => {
617                    insert_keyframe2(
618                        &mut self.border_top_width,
619                        animation_id,
620                        time,
621                        value.top.0.clone(),
622                    );
623                    insert_keyframe2(
624                        &mut self.border_right_width,
625                        animation_id,
626                        time,
627                        value.right.0.clone(),
628                    );
629                    insert_keyframe2(
630                        &mut self.border_bottom_width,
631                        animation_id,
632                        time,
633                        value.bottom.0.clone(),
634                    );
635                    insert_keyframe2(
636                        &mut self.border_left_width,
637                        animation_id,
638                        time,
639                        value.left.0.clone(),
640                    );
641                }
642
643                Property::BorderTopWidth(value) => {
644                    insert_keyframe2(
645                        &mut self.border_top_width,
646                        animation_id,
647                        time,
648                        value.0.clone(),
649                    );
650                }
651
652                Property::BorderRightWidth(value) => {
653                    insert_keyframe2(
654                        &mut self.border_right_width,
655                        animation_id,
656                        time,
657                        value.0.clone(),
658                    );
659                }
660
661                Property::BorderBottomWidth(value) => {
662                    insert_keyframe2(
663                        &mut self.border_bottom_width,
664                        animation_id,
665                        time,
666                        value.0.clone(),
667                    );
668                }
669
670                Property::BorderLeftWidth(value) => {
671                    insert_keyframe2(
672                        &mut self.border_left_width,
673                        animation_id,
674                        time,
675                        value.0.clone(),
676                    );
677                }
678
679                Property::BorderColor(value) => {
680                    insert_keyframe2(&mut self.border_top_color, animation_id, time, *value);
681                    insert_keyframe2(&mut self.border_right_color, animation_id, time, *value);
682                    insert_keyframe2(&mut self.border_bottom_color, animation_id, time, *value);
683                    insert_keyframe2(&mut self.border_left_color, animation_id, time, *value);
684                }
685
686                Property::BorderTopColor(value) => {
687                    insert_keyframe2(&mut self.border_top_color, animation_id, time, *value);
688                }
689
690                Property::BorderRightColor(value) => {
691                    insert_keyframe2(&mut self.border_right_color, animation_id, time, *value);
692                }
693
694                Property::BorderBottomColor(value) => {
695                    insert_keyframe2(&mut self.border_bottom_color, animation_id, time, *value);
696                }
697
698                Property::BorderLeftColor(value) => {
699                    insert_keyframe2(&mut self.border_left_color, animation_id, time, *value);
700                }
701
702                Property::CornerTopLeftRadius(value) => {
703                    insert_keyframe2(
704                        &mut self.corner_top_left_radius,
705                        animation_id,
706                        time,
707                        value.clone(),
708                    );
709                }
710
711                Property::CornerTopRightRadius(value) => {
712                    insert_keyframe2(
713                        &mut self.corner_top_right_radius,
714                        animation_id,
715                        time,
716                        value.clone(),
717                    );
718                }
719
720                Property::CornerBottomLeftRadius(value) => {
721                    insert_keyframe2(
722                        &mut self.corner_bottom_left_radius,
723                        animation_id,
724                        time,
725                        value.clone(),
726                    );
727                }
728
729                Property::CornerBottomRightRadius(value) => {
730                    insert_keyframe2(
731                        &mut self.corner_bottom_right_radius,
732                        animation_id,
733                        time,
734                        value.clone(),
735                    );
736                }
737
738                // OUTLINE
739                Property::OutlineWidth(value) => {
740                    insert_keyframe2(
741                        &mut self.outline_width,
742                        animation_id,
743                        time,
744                        value.left.0.clone(),
745                    );
746                }
747
748                Property::OutlineColor(value) => {
749                    insert_keyframe2(&mut self.outline_color, animation_id, time, *value);
750                }
751
752                Property::OutlineOffset(value) => {
753                    insert_keyframe2(&mut self.outline_offset, animation_id, time, value.clone());
754                }
755
756                // BACKGROUND
757                Property::BackgroundColor(value) => {
758                    insert_keyframe2(&mut self.background_color, animation_id, time, *value);
759                }
760
761                Property::BackgroundImage(images) => {
762                    let images = images
763                        .iter()
764                        .filter_map(|img| match img {
765                            BackgroundImage::None => None,
766                            BackgroundImage::Gradient(gradient) => {
767                                Some(ImageOrGradient::Gradient(*gradient.clone()))
768                            }
769                            BackgroundImage::Url(url) => {
770                                Some(ImageOrGradient::Image(url.url.to_string()))
771                            }
772                        })
773                        .collect::<Vec<_>>();
774                    insert_keyframe(&mut self.background_image, animation_id, time, images);
775                }
776
777                Property::BackgroundPosition(value) => {
778                    insert_keyframe(
779                        &mut self.background_position,
780                        animation_id,
781                        time,
782                        value.clone(),
783                    );
784                }
785
786                Property::BackgroundSize(value) => {
787                    insert_keyframe(&mut self.background_size, animation_id, time, value.clone());
788                }
789
790                Property::BackgroundRepeat(value) => {
791                    insert_keyframe(&mut self.background_repeat, animation_id, time, value.clone());
792                }
793
794                // BOX SHADOW
795                Property::Shadow(value) => {
796                    insert_keyframe2(&mut self.shadow, animation_id, time, value.clone());
797                }
798
799                // TEXT
800                Property::FontColor(value) => {
801                    insert_keyframe2(&mut self.font_color, animation_id, time, *value);
802                }
803
804                Property::FontSize(value) => {
805                    insert_keyframe2(&mut self.font_size, animation_id, time, value.clone());
806                }
807
808                Property::LetterSpacing(value) => {
809                    insert_keyframe2(&mut self.letter_spacing, animation_id, time, value.clone());
810                }
811
812                Property::LineHeight(value) => {
813                    insert_keyframe2(&mut self.line_height, animation_id, time, value.clone());
814                }
815
816                Property::CaretColor(value) => {
817                    insert_keyframe2(&mut self.caret_color, animation_id, time, *value);
818                }
819
820                Property::SelectionColor(value) => {
821                    insert_keyframe2(&mut self.selection_color, animation_id, time, *value);
822                }
823
824                // SPACE
825                Property::Left(value) => {
826                    insert_keyframe2(&mut self.left, animation_id, time, *value);
827                }
828
829                Property::Right(value) => {
830                    insert_keyframe2(&mut self.right, animation_id, time, *value);
831                }
832
833                Property::Top(value) => {
834                    insert_keyframe2(&mut self.top, animation_id, time, *value);
835                }
836
837                Property::Bottom(value) => {
838                    insert_keyframe2(&mut self.bottom, animation_id, time, *value);
839                }
840
841                // Padding
842                Property::PaddingLeft(value) => {
843                    insert_keyframe2(&mut self.padding_left, animation_id, time, *value);
844                }
845
846                Property::PaddingRight(value) => {
847                    insert_keyframe2(&mut self.padding_right, animation_id, time, *value);
848                }
849
850                Property::PaddingTop(value) => {
851                    insert_keyframe2(&mut self.padding_top, animation_id, time, *value);
852                }
853
854                Property::PaddingBottom(value) => {
855                    insert_keyframe2(&mut self.padding_bottom, animation_id, time, *value);
856                }
857
858                Property::HorizontalGap(value) => {
859                    insert_keyframe2(&mut self.horizontal_gap, animation_id, time, *value);
860                }
861
862                Property::VerticalGap(value) => {
863                    insert_keyframe2(&mut self.vertical_gap, animation_id, time, *value);
864                }
865
866                Property::Gap(value) => {
867                    insert_keyframe2(&mut self.horizontal_gap, animation_id, time, *value);
868                    insert_keyframe2(&mut self.vertical_gap, animation_id, time, *value);
869                }
870
871                // GAP CONSSTRAINTS
872                Property::MinGap(value) => {
873                    insert_keyframe2(&mut self.min_horizontal_gap, animation_id, time, *value);
874                    insert_keyframe2(&mut self.min_vertical_gap, animation_id, time, *value);
875                }
876
877                Property::MaxGap(value) => {
878                    insert_keyframe2(&mut self.max_horizontal_gap, animation_id, time, *value);
879                    insert_keyframe2(&mut self.max_vertical_gap, animation_id, time, *value);
880                }
881
882                Property::MinHorizontalGap(value) => {
883                    insert_keyframe2(&mut self.min_horizontal_gap, animation_id, time, *value);
884                }
885
886                Property::MaxHorizontalGap(value) => {
887                    insert_keyframe2(&mut self.max_horizontal_gap, animation_id, time, *value);
888                }
889
890                Property::MinVerticalGap(value) => {
891                    insert_keyframe2(&mut self.min_vertical_gap, animation_id, time, *value);
892                }
893
894                Property::MaxVerticalGap(value) => {
895                    insert_keyframe2(&mut self.max_vertical_gap, animation_id, time, *value);
896                }
897
898                // SIZE
899                Property::Width(value) => {
900                    insert_keyframe2(&mut self.width, animation_id, time, *value);
901                }
902
903                Property::Height(value) => {
904                    insert_keyframe2(&mut self.height, animation_id, time, *value);
905                }
906
907                // SIZE CONSTRAINTS
908                Property::MinWidth(value) => {
909                    insert_keyframe2(&mut self.min_width, animation_id, time, *value);
910                }
911
912                Property::MaxWidth(value) => {
913                    insert_keyframe2(&mut self.max_width, animation_id, time, *value);
914                }
915
916                Property::MinHeight(value) => {
917                    insert_keyframe2(&mut self.min_height, animation_id, time, *value);
918                }
919
920                Property::MaxHeight(value) => {
921                    insert_keyframe2(&mut self.max_height, animation_id, time, *value);
922                }
923
924                Property::TextDecorationColor(value) => {
925                    insert_keyframe2(&mut self.text_decoration_color, animation_id, time, *value);
926                }
927
928                Property::Fill(value) => {
929                    insert_keyframe2(&mut self.fill, animation_id, time, *value);
930                }
931
932                _ => {}
933            }
934        }
935    }
936
937    pub(crate) fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
938        let animation_id = self.animation_manager.create();
939        for keyframe in animation.keyframes.iter() {
940            self.add_keyframe(animation_id, keyframe.time, &keyframe.properties);
941        }
942
943        animation_id
944    }
945
946    pub(crate) fn enqueue_animation(
947        &mut self,
948        entity: Entity,
949        animation: Animation,
950        duration: Duration,
951        delay: Duration,
952    ) {
953        self.pending_animations.push((entity, animation, duration, delay));
954    }
955
956    pub(crate) fn play_pending_animations(&mut self) {
957        let start_time = Instant::now();
958
959        let pending_animations = std::mem::take(&mut self.pending_animations);
960
961        for (entity, animation, duration, delay) in pending_animations {
962            self.play_animation(entity, animation, start_time + delay, duration, delay)
963        }
964    }
965
966    pub(crate) fn play_animation(
967        &mut self,
968        entity: Entity,
969        animation: Animation,
970        start_time: Instant,
971        duration: Duration,
972        delay: Duration,
973    ) {
974        self.display.play_animation(entity, animation, start_time, duration, delay);
975        self.opacity.play_animation(entity, animation, start_time, duration, delay);
976        self.clip_path.play_animation(entity, animation, start_time, duration, delay);
977
978        self.transform.play_animation(entity, animation, start_time, duration, delay);
979        self.transform_origin.play_animation(entity, animation, start_time, duration, delay);
980        self.translate.play_animation(entity, animation, start_time, duration, delay);
981        self.rotate.play_animation(entity, animation, start_time, duration, delay);
982        self.scale.play_animation(entity, animation, start_time, duration, delay);
983
984        self.border_top_width.play_animation(entity, animation, start_time, duration, delay);
985        self.border_right_width.play_animation(entity, animation, start_time, duration, delay);
986        self.border_bottom_width.play_animation(entity, animation, start_time, duration, delay);
987        self.border_left_width.play_animation(entity, animation, start_time, duration, delay);
988        self.border_top_color.play_animation(entity, animation, start_time, duration, delay);
989        self.border_right_color.play_animation(entity, animation, start_time, duration, delay);
990        self.border_bottom_color.play_animation(entity, animation, start_time, duration, delay);
991        self.border_left_color.play_animation(entity, animation, start_time, duration, delay);
992
993        self.corner_top_left_radius.play_animation(entity, animation, start_time, duration, delay);
994        self.corner_top_right_radius.play_animation(entity, animation, start_time, duration, delay);
995        self.corner_bottom_left_radius
996            .play_animation(entity, animation, start_time, duration, delay);
997        self.corner_bottom_right_radius
998            .play_animation(entity, animation, start_time, duration, delay);
999
1000        self.outline_width.play_animation(entity, animation, start_time, duration, delay);
1001        self.outline_color.play_animation(entity, animation, start_time, duration, delay);
1002        self.outline_offset.play_animation(entity, animation, start_time, duration, delay);
1003
1004        self.background_color.play_animation(entity, animation, start_time, duration, delay);
1005        self.background_image.play_animation(entity, animation, start_time, duration, delay);
1006        self.background_position.play_animation(entity, animation, start_time, duration, delay);
1007        self.background_repeat.play_animation(entity, animation, start_time, duration, delay);
1008        self.background_size.play_animation(entity, animation, start_time, duration, delay);
1009
1010        self.shadow.play_animation(entity, animation, start_time, duration, delay);
1011
1012        self.font_color.play_animation(entity, animation, start_time, duration, delay);
1013        self.font_size.play_animation(entity, animation, start_time, duration, delay);
1014        self.letter_spacing.play_animation(entity, animation, start_time, duration, delay);
1015        self.line_height.play_animation(entity, animation, start_time, duration, delay);
1016        self.caret_color.play_animation(entity, animation, start_time, duration, delay);
1017        self.selection_color.play_animation(entity, animation, start_time, duration, delay);
1018
1019        self.left.play_animation(entity, animation, start_time, duration, delay);
1020        self.right.play_animation(entity, animation, start_time, duration, delay);
1021        self.top.play_animation(entity, animation, start_time, duration, delay);
1022        self.bottom.play_animation(entity, animation, start_time, duration, delay);
1023
1024        self.padding_left.play_animation(entity, animation, start_time, duration, delay);
1025        self.padding_right.play_animation(entity, animation, start_time, duration, delay);
1026        self.padding_top.play_animation(entity, animation, start_time, duration, delay);
1027        self.padding_bottom.play_animation(entity, animation, start_time, duration, delay);
1028        self.horizontal_gap.play_animation(entity, animation, start_time, duration, delay);
1029        self.vertical_gap.play_animation(entity, animation, start_time, duration, delay);
1030
1031        self.width.play_animation(entity, animation, start_time, duration, delay);
1032        self.height.play_animation(entity, animation, start_time, duration, delay);
1033
1034        self.min_width.play_animation(entity, animation, start_time, duration, delay);
1035        self.max_width.play_animation(entity, animation, start_time, duration, delay);
1036        self.min_height.play_animation(entity, animation, start_time, duration, delay);
1037        self.max_height.play_animation(entity, animation, start_time, duration, delay);
1038
1039        self.min_horizontal_gap.play_animation(entity, animation, start_time, duration, delay);
1040        self.max_horizontal_gap.play_animation(entity, animation, start_time, duration, delay);
1041        self.min_vertical_gap.play_animation(entity, animation, start_time, duration, delay);
1042        self.max_vertical_gap.play_animation(entity, animation, start_time, duration, delay);
1043
1044        self.text_decoration_color.play_animation(entity, animation, start_time, duration, delay);
1045
1046        self.fill.play_animation(entity, animation, start_time, duration, delay);
1047
1048        // Play animations on custom color properties
1049        for store in self.custom_color_props.values_mut() {
1050            store.play_animation(entity, animation, start_time, duration, delay);
1051        }
1052        // Play animations on custom length properties
1053        for store in self.custom_length_props.values_mut() {
1054            store.play_animation(entity, animation, start_time, duration, delay);
1055        }
1056        // Play animations on custom font-size properties
1057        for store in self.custom_font_size_props.values_mut() {
1058            store.play_animation(entity, animation, start_time, duration, delay);
1059        }
1060        // Play animations on custom letter-spacing properties
1061        for store in self.custom_letter_spacing_props.values_mut() {
1062            store.play_animation(entity, animation, start_time, duration, delay);
1063        }
1064        // Play animations on custom line-height properties
1065        for store in self.custom_line_height_props.values_mut() {
1066            store.play_animation(entity, animation, start_time, duration, delay);
1067        }
1068        // Play animations on custom units properties
1069        for store in self.custom_units_props.values_mut() {
1070            store.play_animation(entity, animation, start_time, duration, delay);
1071        }
1072        // Play animations on custom opacity properties
1073        for store in self.custom_opacity_props.values_mut() {
1074            store.play_animation(entity, animation, start_time, duration, delay);
1075        }
1076        // Play animations on custom shadow properties
1077        for store in self.custom_shadow_props.values_mut() {
1078            store.play_animation(entity, animation, start_time, duration, delay);
1079        }
1080    }
1081
1082    pub(crate) fn is_animating(&self, entity: Entity, animation: Animation) -> bool {
1083        self.display.has_active_animation(entity, animation)
1084            | self.opacity.has_active_animation(entity, animation)
1085            | self.clip_path.has_active_animation(entity, animation)
1086            | self.transform.has_active_animation(entity, animation)
1087            | self.transform_origin.has_active_animation(entity, animation)
1088            | self.translate.has_active_animation(entity, animation)
1089            | self.rotate.has_active_animation(entity, animation)
1090            | self.scale.has_active_animation(entity, animation)
1091            | self.border_top_width.has_active_animation(entity, animation)
1092            | self.border_right_width.has_active_animation(entity, animation)
1093            | self.border_bottom_width.has_active_animation(entity, animation)
1094            | self.border_left_width.has_active_animation(entity, animation)
1095            | self.border_top_color.has_active_animation(entity, animation)
1096            | self.border_right_color.has_active_animation(entity, animation)
1097            | self.border_bottom_color.has_active_animation(entity, animation)
1098            | self.border_left_color.has_active_animation(entity, animation)
1099            | self.corner_top_left_radius.has_active_animation(entity, animation)
1100            | self.corner_top_right_radius.has_active_animation(entity, animation)
1101            | self.corner_bottom_left_radius.has_active_animation(entity, animation)
1102            | self.corner_bottom_right_radius.has_active_animation(entity, animation)
1103            | self.outline_width.has_active_animation(entity, animation)
1104            | self.outline_color.has_active_animation(entity, animation)
1105            | self.outline_offset.has_active_animation(entity, animation)
1106            | self.background_color.has_active_animation(entity, animation)
1107            | self.background_image.has_active_animation(entity, animation)
1108            | self.background_position.has_active_animation(entity, animation)
1109            | self.background_repeat.has_active_animation(entity, animation)
1110            | self.background_size.has_active_animation(entity, animation)
1111            | self.shadow.has_active_animation(entity, animation)
1112            | self.font_color.has_active_animation(entity, animation)
1113            | self.font_size.has_active_animation(entity, animation)
1114            | self.letter_spacing.has_active_animation(entity, animation)
1115            | self.line_height.has_active_animation(entity, animation)
1116            | self.caret_color.has_active_animation(entity, animation)
1117            | self.selection_color.has_active_animation(entity, animation)
1118            | self.left.has_active_animation(entity, animation)
1119            | self.right.has_active_animation(entity, animation)
1120            | self.top.has_active_animation(entity, animation)
1121            | self.bottom.has_active_animation(entity, animation)
1122            | self.padding_left.has_active_animation(entity, animation)
1123            | self.padding_right.has_active_animation(entity, animation)
1124            | self.padding_top.has_active_animation(entity, animation)
1125            | self.padding_bottom.has_active_animation(entity, animation)
1126            | self.horizontal_gap.has_active_animation(entity, animation)
1127            | self.vertical_gap.has_active_animation(entity, animation)
1128            | self.width.has_active_animation(entity, animation)
1129            | self.height.has_active_animation(entity, animation)
1130            | self.min_width.has_active_animation(entity, animation)
1131            | self.max_width.has_active_animation(entity, animation)
1132            | self.min_height.has_active_animation(entity, animation)
1133            | self.max_height.has_active_animation(entity, animation)
1134            | self.min_horizontal_gap.has_active_animation(entity, animation)
1135            | self.max_horizontal_gap.has_active_animation(entity, animation)
1136            | self.min_vertical_gap.has_active_animation(entity, animation)
1137            | self.max_vertical_gap.has_active_animation(entity, animation)
1138            | self.text_decoration_color.has_active_animation(entity, animation)
1139            | self.fill.has_active_animation(entity, animation)
1140    }
1141
1142    pub(crate) fn parse_theme(&mut self, stylesheet: &str) {
1143        if let Ok(stylesheet) = StyleSheet::parse(stylesheet, ParserOptions::new()) {
1144            let rules = stylesheet.rules.0;
1145
1146            for rule in rules {
1147                match rule {
1148                    CssRule::Style(style_rule) => {
1149                        // let selectors = style_rule.selectors;
1150
1151                        for selector in style_rule.selectors.slice() {
1152                            let rule_id = self.rule_manager.create();
1153
1154                            for property in style_rule.declarations.declarations.iter() {
1155                                match property {
1156                                    Property::Transition(transitions) => {
1157                                        for transition in transitions.iter() {
1158                                            self.insert_transition(rule_id, transition);
1159                                        }
1160                                    }
1161
1162                                    _ => {
1163                                        self.insert_property(rule_id, property);
1164                                    }
1165                                }
1166                            }
1167
1168                            self.rules.insert(rule_id, StyleRule::new(selector.clone()));
1169                        }
1170                    }
1171
1172                    CssRule::Keyframes(keyframes_rule) => {
1173                        let name = keyframes_rule.name.as_string();
1174
1175                        let animation_id = self.animation_manager.create();
1176
1177                        for keyframes in keyframes_rule.keyframes {
1178                            for selector in keyframes.selectors.iter() {
1179                                let time = match selector {
1180                                    KeyframeSelector::From => 0.0,
1181                                    KeyframeSelector::To => 1.0,
1182                                    KeyframeSelector::Percentage(percentage) => {
1183                                        percentage.0 / 100.0
1184                                    }
1185                                };
1186
1187                                self.add_keyframe(
1188                                    animation_id,
1189                                    time,
1190                                    &keyframes.declarations.declarations,
1191                                );
1192                            }
1193                        }
1194
1195                        self.animations.insert(name, animation_id);
1196                    }
1197
1198                    _ => {}
1199                }
1200            }
1201        } else {
1202            println!("Failed to parse stylesheet");
1203        }
1204    }
1205
1206    fn insert_transition(&mut self, rule_id: Rule, transition: &Transition) {
1207        let animation = self.animation_manager.create();
1208        match transition.property.as_ref() {
1209            "display" => {
1210                self.display.insert_animation(animation, self.add_transition(transition));
1211                self.display.insert_transition(rule_id, animation);
1212            }
1213
1214            "opacity" => {
1215                self.opacity.insert_animation(animation, self.add_transition(transition));
1216                self.opacity.insert_transition(rule_id, animation);
1217            }
1218
1219            "clip-path" => {
1220                self.clip_path.insert_animation(animation, self.add_transition(transition));
1221                self.clip_path.insert_transition(rule_id, animation);
1222            }
1223
1224            "transform" => {
1225                self.transform.insert_animation(animation, self.add_transition(transition));
1226                self.transform.insert_transition(rule_id, animation);
1227            }
1228
1229            "transform-origin" => {
1230                self.transform_origin.insert_animation(animation, self.add_transition(transition));
1231                self.transform_origin.insert_transition(rule_id, animation);
1232            }
1233
1234            "translate" => {
1235                self.translate.insert_animation(animation, self.add_transition(transition));
1236                self.translate.insert_transition(rule_id, animation);
1237            }
1238
1239            "rotate" => {
1240                self.rotate.insert_animation(animation, self.add_transition(transition));
1241                self.rotate.insert_transition(rule_id, animation);
1242            }
1243
1244            "scale" => {
1245                self.scale.insert_animation(animation, self.add_transition(transition));
1246                self.scale.insert_transition(rule_id, animation);
1247            }
1248
1249            "border" => {
1250                self.border_top_width.insert_animation(animation, self.add_transition(transition));
1251                self.border_top_width.insert_transition(rule_id, animation);
1252                self.border_right_width
1253                    .insert_animation(animation, self.add_transition(transition));
1254                self.border_right_width.insert_transition(rule_id, animation);
1255                self.border_bottom_width
1256                    .insert_animation(animation, self.add_transition(transition));
1257                self.border_bottom_width.insert_transition(rule_id, animation);
1258                self.border_left_width.insert_animation(animation, self.add_transition(transition));
1259                self.border_left_width.insert_transition(rule_id, animation);
1260                self.border_top_color.insert_animation(animation, self.add_transition(transition));
1261                self.border_top_color.insert_transition(rule_id, animation);
1262                self.border_right_color
1263                    .insert_animation(animation, self.add_transition(transition));
1264                self.border_right_color.insert_transition(rule_id, animation);
1265                self.border_bottom_color
1266                    .insert_animation(animation, self.add_transition(transition));
1267                self.border_bottom_color.insert_transition(rule_id, animation);
1268                self.border_left_color.insert_animation(animation, self.add_transition(transition));
1269                self.border_left_color.insert_transition(rule_id, animation);
1270            }
1271
1272            "border-width" => {
1273                self.border_top_width.insert_animation(animation, self.add_transition(transition));
1274                self.border_top_width.insert_transition(rule_id, animation);
1275                self.border_right_width
1276                    .insert_animation(animation, self.add_transition(transition));
1277                self.border_right_width.insert_transition(rule_id, animation);
1278                self.border_bottom_width
1279                    .insert_animation(animation, self.add_transition(transition));
1280                self.border_bottom_width.insert_transition(rule_id, animation);
1281                self.border_left_width.insert_animation(animation, self.add_transition(transition));
1282                self.border_left_width.insert_transition(rule_id, animation);
1283            }
1284
1285            "border-top" => {
1286                self.border_top_width.insert_animation(animation, self.add_transition(transition));
1287                self.border_top_width.insert_transition(rule_id, animation);
1288                self.border_top_color.insert_animation(animation, self.add_transition(transition));
1289                self.border_top_color.insert_transition(rule_id, animation);
1290            }
1291
1292            "border-right" => {
1293                self.border_right_width
1294                    .insert_animation(animation, self.add_transition(transition));
1295                self.border_right_width.insert_transition(rule_id, animation);
1296                self.border_right_color
1297                    .insert_animation(animation, self.add_transition(transition));
1298                self.border_right_color.insert_transition(rule_id, animation);
1299            }
1300
1301            "border-bottom" => {
1302                self.border_bottom_width
1303                    .insert_animation(animation, self.add_transition(transition));
1304                self.border_bottom_width.insert_transition(rule_id, animation);
1305                self.border_bottom_color
1306                    .insert_animation(animation, self.add_transition(transition));
1307                self.border_bottom_color.insert_transition(rule_id, animation);
1308            }
1309
1310            "border-left" => {
1311                self.border_left_width.insert_animation(animation, self.add_transition(transition));
1312                self.border_left_width.insert_transition(rule_id, animation);
1313                self.border_left_color.insert_animation(animation, self.add_transition(transition));
1314                self.border_left_color.insert_transition(rule_id, animation);
1315            }
1316
1317            "border-top-width" => {
1318                self.border_top_width.insert_animation(animation, self.add_transition(transition));
1319                self.border_top_width.insert_transition(rule_id, animation);
1320            }
1321
1322            "border-right-width" => {
1323                self.border_right_width
1324                    .insert_animation(animation, self.add_transition(transition));
1325                self.border_right_width.insert_transition(rule_id, animation);
1326            }
1327
1328            "border-bottom-width" => {
1329                self.border_bottom_width
1330                    .insert_animation(animation, self.add_transition(transition));
1331                self.border_bottom_width.insert_transition(rule_id, animation);
1332            }
1333
1334            "border-left-width" => {
1335                self.border_left_width.insert_animation(animation, self.add_transition(transition));
1336                self.border_left_width.insert_transition(rule_id, animation);
1337            }
1338
1339            "border-color" => {
1340                self.border_top_color.insert_animation(animation, self.add_transition(transition));
1341                self.border_top_color.insert_transition(rule_id, animation);
1342                self.border_right_color
1343                    .insert_animation(animation, self.add_transition(transition));
1344                self.border_right_color.insert_transition(rule_id, animation);
1345                self.border_bottom_color
1346                    .insert_animation(animation, self.add_transition(transition));
1347                self.border_bottom_color.insert_transition(rule_id, animation);
1348                self.border_left_color.insert_animation(animation, self.add_transition(transition));
1349                self.border_left_color.insert_transition(rule_id, animation);
1350            }
1351
1352            "border-top-color" => {
1353                self.border_top_color.insert_animation(animation, self.add_transition(transition));
1354                self.border_top_color.insert_transition(rule_id, animation);
1355            }
1356
1357            "border-right-color" => {
1358                self.border_right_color
1359                    .insert_animation(animation, self.add_transition(transition));
1360                self.border_right_color.insert_transition(rule_id, animation);
1361            }
1362
1363            "border-bottom-color" => {
1364                self.border_bottom_color
1365                    .insert_animation(animation, self.add_transition(transition));
1366                self.border_bottom_color.insert_transition(rule_id, animation);
1367            }
1368
1369            "border-left-color" => {
1370                self.border_left_color.insert_animation(animation, self.add_transition(transition));
1371                self.border_left_color.insert_transition(rule_id, animation);
1372            }
1373
1374            "corner-radius" => {
1375                self.corner_bottom_left_radius
1376                    .insert_animation(animation, self.add_transition(transition));
1377                self.corner_bottom_left_radius.insert_transition(rule_id, animation);
1378                self.corner_bottom_right_radius
1379                    .insert_animation(animation, self.add_transition(transition));
1380                self.corner_bottom_right_radius.insert_transition(rule_id, animation);
1381                self.corner_top_left_radius
1382                    .insert_animation(animation, self.add_transition(transition));
1383                self.corner_top_left_radius.insert_transition(rule_id, animation);
1384                self.corner_top_right_radius
1385                    .insert_animation(animation, self.add_transition(transition));
1386                self.corner_top_right_radius.insert_transition(rule_id, animation);
1387            }
1388
1389            "corner-top-left-radius" => {
1390                self.corner_top_left_radius
1391                    .insert_animation(animation, self.add_transition(transition));
1392                self.corner_top_left_radius.insert_transition(rule_id, animation);
1393            }
1394
1395            "corner-top-right-radius" => {
1396                self.corner_top_right_radius
1397                    .insert_animation(animation, self.add_transition(transition));
1398                self.corner_top_right_radius.insert_transition(rule_id, animation);
1399            }
1400
1401            "corner-bottom-left-radius" => {
1402                self.corner_bottom_left_radius
1403                    .insert_animation(animation, self.add_transition(transition));
1404                self.corner_bottom_left_radius.insert_transition(rule_id, animation);
1405            }
1406
1407            "corner-bottom-right-radius" => {
1408                self.corner_bottom_right_radius
1409                    .insert_animation(animation, self.add_transition(transition));
1410                self.corner_bottom_right_radius.insert_transition(rule_id, animation);
1411            }
1412
1413            "outline" => {
1414                self.outline_width.insert_animation(animation, self.add_transition(transition));
1415                self.outline_width.insert_transition(rule_id, animation);
1416                self.outline_color.insert_animation(animation, self.add_transition(transition));
1417                self.outline_color.insert_transition(rule_id, animation);
1418            }
1419
1420            "outline-width" => {
1421                self.outline_width.insert_animation(animation, self.add_transition(transition));
1422                self.outline_width.insert_transition(rule_id, animation);
1423            }
1424
1425            "outline-color" => {
1426                self.outline_color.insert_animation(animation, self.add_transition(transition));
1427                self.outline_color.insert_transition(rule_id, animation);
1428            }
1429
1430            "outline-offset" => {
1431                self.outline_offset.insert_animation(animation, self.add_transition(transition));
1432                self.outline_offset.insert_transition(rule_id, animation);
1433            }
1434
1435            "background-color" => {
1436                self.background_color.insert_animation(animation, self.add_transition(transition));
1437                self.background_color.insert_transition(rule_id, animation);
1438            }
1439
1440            "background-image" => {
1441                self.background_image.insert_animation(animation, self.add_transition(transition));
1442                self.background_image.insert_transition(rule_id, animation);
1443            }
1444
1445            "background-position" => {
1446                self.background_position
1447                    .insert_animation(animation, self.add_transition(transition));
1448                self.background_position.insert_transition(rule_id, animation);
1449            }
1450
1451            "background-size" => {
1452                self.background_size.insert_animation(animation, self.add_transition(transition));
1453                self.background_size.insert_transition(rule_id, animation);
1454            }
1455
1456            "background-repeat" => {
1457                self.background_repeat.insert_animation(animation, self.add_transition(transition));
1458                self.background_repeat.insert_transition(rule_id, animation);
1459            }
1460
1461            "shadow" => {
1462                self.shadow.insert_animation(animation, self.add_transition(transition));
1463                self.shadow.insert_transition(rule_id, animation);
1464            }
1465
1466            "color" => {
1467                self.font_color.insert_animation(animation, self.add_transition(transition));
1468                self.font_color.insert_transition(rule_id, animation);
1469            }
1470
1471            "font-size" => {
1472                self.font_size.insert_animation(animation, self.add_transition(transition));
1473                self.font_size.insert_transition(rule_id, animation);
1474            }
1475
1476            "letter-spacing" => {
1477                self.letter_spacing.insert_animation(animation, self.add_transition(transition));
1478                self.letter_spacing.insert_transition(rule_id, animation);
1479            }
1480
1481            "line-height" => {
1482                self.line_height.insert_animation(animation, self.add_transition(transition));
1483                self.line_height.insert_transition(rule_id, animation);
1484            }
1485
1486            "caret-color" => {
1487                self.caret_color.insert_animation(animation, self.add_transition(transition));
1488                self.caret_color.insert_transition(rule_id, animation);
1489            }
1490
1491            "selection-color" => {
1492                self.selection_color.insert_animation(animation, self.add_transition(transition));
1493                self.selection_color.insert_transition(rule_id, animation);
1494            }
1495
1496            "left" => {
1497                self.left.insert_animation(animation, self.add_transition(transition));
1498                self.left.insert_transition(rule_id, animation);
1499            }
1500
1501            "right" => {
1502                self.right.insert_animation(animation, self.add_transition(transition));
1503                self.right.insert_transition(rule_id, animation);
1504            }
1505
1506            "top" => {
1507                self.top.insert_animation(animation, self.add_transition(transition));
1508                self.top.insert_transition(rule_id, animation);
1509            }
1510
1511            "bottom" => {
1512                self.bottom.insert_animation(animation, self.add_transition(transition));
1513                self.bottom.insert_transition(rule_id, animation);
1514            }
1515
1516            "padding-left" => {
1517                self.padding_left.insert_animation(animation, self.add_transition(transition));
1518                self.padding_left.insert_transition(rule_id, animation);
1519            }
1520
1521            "padding-right" => {
1522                self.padding_right.insert_animation(animation, self.add_transition(transition));
1523                self.padding_right.insert_transition(rule_id, animation);
1524            }
1525
1526            "padding-top" => {
1527                self.padding_top.insert_animation(animation, self.add_transition(transition));
1528                self.padding_top.insert_transition(rule_id, animation);
1529            }
1530
1531            "padding-bottom" => {
1532                self.padding_bottom.insert_animation(animation, self.add_transition(transition));
1533                self.padding_bottom.insert_transition(rule_id, animation);
1534            }
1535
1536            "horizontal-gap" => {
1537                self.horizontal_gap.insert_animation(animation, self.add_transition(transition));
1538                self.horizontal_gap.insert_transition(rule_id, animation);
1539            }
1540
1541            "vertical-gap" => {
1542                self.vertical_gap.insert_animation(animation, self.add_transition(transition));
1543                self.vertical_gap.insert_transition(rule_id, animation);
1544            }
1545
1546            "gap" => {
1547                self.horizontal_gap.insert_animation(animation, self.add_transition(transition));
1548                self.horizontal_gap.insert_transition(rule_id, animation);
1549                self.vertical_gap.insert_animation(animation, self.add_transition(transition));
1550                self.vertical_gap.insert_transition(rule_id, animation);
1551            }
1552
1553            "width" => {
1554                self.width.insert_animation(animation, self.add_transition(transition));
1555                self.width.insert_transition(rule_id, animation);
1556            }
1557
1558            "height" => {
1559                self.height.insert_animation(animation, self.add_transition(transition));
1560                self.height.insert_transition(rule_id, animation);
1561            }
1562
1563            "min-width" => {
1564                self.min_width.insert_animation(animation, self.add_transition(transition));
1565                self.min_width.insert_transition(rule_id, animation);
1566            }
1567
1568            "max-width" => {
1569                self.max_width.insert_animation(animation, self.add_transition(transition));
1570                self.max_width.insert_transition(rule_id, animation);
1571            }
1572
1573            "min-height" => {
1574                self.min_height.insert_animation(animation, self.add_transition(transition));
1575                self.min_height.insert_transition(rule_id, animation);
1576            }
1577
1578            "max-height" => {
1579                self.max_height.insert_animation(animation, self.add_transition(transition));
1580                self.max_height.insert_transition(rule_id, animation);
1581            }
1582
1583            "min-horizontal-gap" => {
1584                self.min_horizontal_gap
1585                    .insert_animation(animation, self.add_transition(transition));
1586                self.min_horizontal_gap.insert_transition(rule_id, animation);
1587            }
1588
1589            "max-horizontal-gap" => {
1590                self.max_horizontal_gap
1591                    .insert_animation(animation, self.add_transition(transition));
1592                self.max_horizontal_gap.insert_transition(rule_id, animation);
1593            }
1594
1595            "min-vertical-gap" => {
1596                self.min_vertical_gap.insert_animation(animation, self.add_transition(transition));
1597                self.min_vertical_gap.insert_transition(rule_id, animation);
1598            }
1599
1600            "max-vertical-gap" => {
1601                self.max_vertical_gap.insert_animation(animation, self.add_transition(transition));
1602                self.max_vertical_gap.insert_transition(rule_id, animation);
1603            }
1604
1605            "text-decoration-color" => {
1606                self.text_decoration_color
1607                    .insert_animation(animation, self.add_transition(transition));
1608                self.text_decoration_color.insert_transition(rule_id, animation);
1609            }
1610
1611            "fill" => {
1612                self.fill.insert_animation(animation, self.add_transition(transition));
1613                self.fill.insert_transition(rule_id, animation);
1614            }
1615
1616            property_name if property_name.starts_with("--") => {
1617                let mut s = DefaultHasher::new();
1618                property_name.hash(&mut s);
1619                let variable_name_hash = s.finish();
1620                // Pre-compute one typed AnimationState per store before taking any mutable
1621                // borrows (add_transition takes &self so this is fine).
1622                let anim_color: AnimationState<Color> = self.add_transition(transition);
1623                let anim_length: AnimationState<LengthOrPercentage> =
1624                    self.add_transition(transition);
1625                let anim_font_size: AnimationState<FontSize> = self.add_transition(transition);
1626                let anim_letter_spacing: AnimationState<LetterSpacing> =
1627                    self.add_transition(transition);
1628                let anim_line_height: AnimationState<LineHeight> = self.add_transition(transition);
1629                let anim_units: AnimationState<Units> = self.add_transition(transition);
1630                let anim_opacity: AnimationState<Opacity> = self.add_transition(transition);
1631
1632                // Register in every custom-property store so whichever store the variable's
1633                // concrete value ends up in will actually animate.
1634                if let Some(store) = self.custom_color_props.get_mut(&variable_name_hash) {
1635                    store.insert_animation(animation, anim_color);
1636                    store.insert_transition(rule_id, animation);
1637                } else {
1638                    let mut store = AnimatableVarSet::default();
1639                    store.insert_animation(animation, anim_color);
1640                    store.insert_transition(rule_id, animation);
1641                    self.custom_color_props.insert(variable_name_hash, store);
1642                }
1643
1644                if let Some(store) = self.custom_length_props.get_mut(&variable_name_hash) {
1645                    store.insert_animation(animation, anim_length);
1646                    store.insert_transition(rule_id, animation);
1647                } else {
1648                    let mut store = AnimatableVarSet::default();
1649                    store.insert_animation(animation, anim_length);
1650                    store.insert_transition(rule_id, animation);
1651                    self.custom_length_props.insert(variable_name_hash, store);
1652                }
1653
1654                if let Some(store) = self.custom_font_size_props.get_mut(&variable_name_hash) {
1655                    store.insert_animation(animation, anim_font_size);
1656                    store.insert_transition(rule_id, animation);
1657                } else {
1658                    let mut store = AnimatableVarSet::default();
1659                    store.insert_animation(animation, anim_font_size);
1660                    store.insert_transition(rule_id, animation);
1661                    self.custom_font_size_props.insert(variable_name_hash, store);
1662                }
1663
1664                if let Some(store) = self.custom_letter_spacing_props.get_mut(&variable_name_hash) {
1665                    store.insert_animation(animation, anim_letter_spacing);
1666                    store.insert_transition(rule_id, animation);
1667                } else {
1668                    let mut store = AnimatableVarSet::default();
1669                    store.insert_animation(animation, anim_letter_spacing);
1670                    store.insert_transition(rule_id, animation);
1671                    self.custom_letter_spacing_props.insert(variable_name_hash, store);
1672                }
1673
1674                if let Some(store) = self.custom_line_height_props.get_mut(&variable_name_hash) {
1675                    store.insert_animation(animation, anim_line_height);
1676                    store.insert_transition(rule_id, animation);
1677                } else {
1678                    let mut store = AnimatableVarSet::default();
1679                    store.insert_animation(animation, anim_line_height);
1680                    store.insert_transition(rule_id, animation);
1681                    self.custom_line_height_props.insert(variable_name_hash, store);
1682                }
1683
1684                if let Some(store) = self.custom_units_props.get_mut(&variable_name_hash) {
1685                    store.insert_animation(animation, anim_units);
1686                    store.insert_transition(rule_id, animation);
1687                } else {
1688                    let mut store = AnimatableVarSet::default();
1689                    store.insert_animation(animation, anim_units);
1690                    store.insert_transition(rule_id, animation);
1691                    self.custom_units_props.insert(variable_name_hash, store);
1692                }
1693
1694                if let Some(store) = self.custom_opacity_props.get_mut(&variable_name_hash) {
1695                    store.insert_animation(animation, anim_opacity);
1696                    store.insert_transition(rule_id, animation);
1697                } else {
1698                    let mut store = AnimatableVarSet::default();
1699                    store.insert_animation(animation, anim_opacity);
1700                    store.insert_transition(rule_id, animation);
1701                    self.custom_opacity_props.insert(variable_name_hash, store);
1702                }
1703            }
1704
1705            _ => {}
1706        }
1707    }
1708
1709    fn insert_property(&mut self, rule_id: Rule, property: &Property) {
1710        fn variable_hash(var: &Variable<'_>) -> u64 {
1711            let mut s = DefaultHasher::new();
1712            var.name.hash(&mut s);
1713            s.finish()
1714        }
1715
1716        fn first_fallback_token<'i>(var: &'i Variable<'i>) -> Option<&'i TokenOrValue<'i>> {
1717            var.fallback.as_ref().and_then(|TokenList(tokens)| tokens.first())
1718        }
1719
1720        fn color_fallback(var: &Variable<'_>) -> Option<Color> {
1721            match first_fallback_token(var) {
1722                Some(TokenOrValue::Color(color)) => Some(*color),
1723                _ => None,
1724            }
1725        }
1726
1727        fn length_fallback(var: &Variable<'_>) -> Option<LengthOrPercentage> {
1728            match first_fallback_token(var) {
1729                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1730                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1731                {
1732                    Some(LengthOrPercentage::Length(Length::Value(LengthValue::Px(*value))))
1733                }
1734
1735                Some(TokenOrValue::Token(CssToken::Percentage { unit_value, .. })) => {
1736                    Some(LengthOrPercentage::Percentage(*unit_value * 100.0))
1737                }
1738
1739                _ => None,
1740            }
1741        }
1742
1743        fn font_size_fallback(var: &Variable<'_>) -> Option<FontSize> {
1744            match first_fallback_token(var) {
1745                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1746                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1747                {
1748                    Some(FontSize(Length::Value(LengthValue::Px(*value))))
1749                }
1750
1751                _ => None,
1752            }
1753        }
1754
1755        fn letter_spacing_fallback(var: &Variable<'_>) -> Option<LetterSpacing> {
1756            match first_fallback_token(var) {
1757                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1758                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1759                {
1760                    Some(LetterSpacing::Length(Length::Value(LengthValue::Px(*value))))
1761                }
1762
1763                Some(TokenOrValue::Token(CssToken::Ident(ident)))
1764                    if ident.as_ref().eq_ignore_ascii_case("normal") =>
1765                {
1766                    Some(LetterSpacing::Normal)
1767                }
1768
1769                _ => None,
1770            }
1771        }
1772
1773        fn line_height_fallback(var: &Variable<'_>) -> Option<LineHeight> {
1774            match first_fallback_token(var) {
1775                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1776                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1777                {
1778                    Some(LineHeight::Length(Length::Value(LengthValue::Px(*value))))
1779                }
1780
1781                Some(TokenOrValue::Token(CssToken::Percentage { unit_value, .. })) => {
1782                    Some(LineHeight::Percentage(*unit_value * 100.0))
1783                }
1784
1785                Some(TokenOrValue::Token(CssToken::Number { value, .. })) => {
1786                    Some(LineHeight::Number(*value))
1787                }
1788
1789                Some(TokenOrValue::Token(CssToken::Ident(ident)))
1790                    if ident.as_ref().eq_ignore_ascii_case("normal") =>
1791                {
1792                    Some(LineHeight::Normal)
1793                }
1794
1795                _ => None,
1796            }
1797        }
1798
1799        fn units_fallback(var: &Variable<'_>) -> Option<Units> {
1800            match first_fallback_token(var) {
1801                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1802                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1803                {
1804                    Some(Units::Pixels(*value))
1805                }
1806
1807                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1808                    if unit.as_ref().eq_ignore_ascii_case("s") =>
1809                {
1810                    Some(Units::Stretch(*value))
1811                }
1812
1813                Some(TokenOrValue::Token(CssToken::Ident(ident)))
1814                    if ident.as_ref().eq_ignore_ascii_case("auto") =>
1815                {
1816                    Some(Units::Auto)
1817                }
1818
1819                Some(TokenOrValue::Token(CssToken::Percentage { unit_value, .. })) => {
1820                    Some(Units::Percentage(*unit_value * 100.0))
1821                }
1822
1823                _ => None,
1824            }
1825        }
1826
1827        fn opacity_fallback(var: &Variable<'_>) -> Option<Opacity> {
1828            match first_fallback_token(var) {
1829                Some(TokenOrValue::Token(CssToken::Percentage { unit_value, .. })) => {
1830                    Some(Opacity(*unit_value))
1831                }
1832
1833                Some(TokenOrValue::Token(CssToken::Number { value, .. })) => Some(Opacity(*value)),
1834
1835                _ => None,
1836            }
1837        }
1838
1839        fn parse_shadow_list(tokens: &[TokenOrValue<'_>]) -> Option<Vec<Shadow>> {
1840            fn parse_shadow_length(token: &TokenOrValue<'_>) -> Option<Length> {
1841                match token {
1842                    TokenOrValue::Token(CssToken::Dimension { value, unit, .. })
1843                        if unit.as_ref().eq_ignore_ascii_case("px") =>
1844                    {
1845                        Some(Length::Value(LengthValue::Px(*value)))
1846                    }
1847
1848                    TokenOrValue::Token(CssToken::Number { value, .. }) if *value == 0.0 => {
1849                        Some(Length::Value(LengthValue::Px(0.0)))
1850                    }
1851
1852                    _ => None,
1853                }
1854            }
1855
1856            fn parse_single_shadow(tokens: &[TokenOrValue<'_>]) -> Option<Shadow> {
1857                let mut lengths: Vec<Length> = Vec::new();
1858                let mut color = None;
1859                let mut inset = false;
1860
1861                for token in tokens {
1862                    match token {
1863                        TokenOrValue::Token(CssToken::WhiteSpace(_)) => {}
1864
1865                        TokenOrValue::Color(c) => {
1866                            if color.is_some() {
1867                                return None;
1868                            }
1869                            color = Some(*c);
1870                        }
1871
1872                        TokenOrValue::Token(CssToken::Ident(ident))
1873                            if ident.as_ref().eq_ignore_ascii_case("inset") =>
1874                        {
1875                            if inset {
1876                                return None;
1877                            }
1878                            inset = true;
1879                        }
1880
1881                        other => {
1882                            let length = parse_shadow_length(other)?;
1883                            lengths.push(length);
1884                        }
1885                    }
1886                }
1887
1888                if !(2..=4).contains(&lengths.len()) {
1889                    return None;
1890                }
1891
1892                let x_offset = lengths[0].clone();
1893                let y_offset = lengths[1].clone();
1894                let blur_radius = lengths.get(2).cloned();
1895                let spread_radius = lengths.get(3).cloned();
1896
1897                Some(Shadow::new(x_offset, y_offset, blur_radius, spread_radius, color, inset))
1898            }
1899
1900            let mut parts = Vec::<&[TokenOrValue<'_>]>::new();
1901            let mut start = 0usize;
1902            for (idx, token) in tokens.iter().enumerate() {
1903                if matches!(token, TokenOrValue::Token(CssToken::Comma)) {
1904                    parts.push(&tokens[start..idx]);
1905                    start = idx + 1;
1906                }
1907            }
1908            parts.push(&tokens[start..]);
1909
1910            let mut parsed = Vec::new();
1911            for part in parts {
1912                let shadow = parse_single_shadow(part)?;
1913                parsed.push(shadow);
1914            }
1915
1916            Some(parsed)
1917        }
1918
1919        fn shadow_fallback(var: &Variable<'_>) -> Option<Vec<Shadow>> {
1920            var.fallback.as_ref().and_then(|TokenList(tokens)| parse_shadow_list(tokens))
1921        }
1922
1923        match property.clone() {
1924            // Display
1925            Property::Display(display) => {
1926                self.display.insert_rule(rule_id, display);
1927            }
1928
1929            // Visibility
1930            Property::Visibility(visibility) => {
1931                self.visibility.insert_rule(rule_id, visibility);
1932            }
1933
1934            // Opacity
1935            Property::Opacity(opacity) => {
1936                self.opacity.insert_rule(rule_id, opacity);
1937            }
1938
1939            // Clipping
1940            Property::ClipPath(clip) => {
1941                self.clip_path.insert_rule(rule_id, clip);
1942            }
1943
1944            // Filters
1945            Property::Filter(filter) => {
1946                self.filter.insert_rule(rule_id, filter);
1947            }
1948
1949            Property::BackdropFilter(filter) => {
1950                self.backdrop_filter.insert_rule(rule_id, filter);
1951            }
1952
1953            // Blend Mode
1954            Property::BlendMode(blend_mode) => {
1955                self.blend_mode.insert_rule(rule_id, blend_mode);
1956            }
1957
1958            // Layout Type
1959            Property::LayoutType(layout_type) => {
1960                self.layout_type.insert_rule(rule_id, layout_type);
1961            }
1962
1963            // Position Type
1964            Property::PositionType(position) => {
1965                self.position_type.insert_rule(rule_id, position);
1966            }
1967
1968            Property::Alignment(alignment) => {
1969                self.alignment.insert_rule(rule_id, alignment);
1970            }
1971
1972            Property::Direction(direction) => {
1973                self.direction.insert_rule(rule_id, direction);
1974            }
1975
1976            Property::Wrap(value) => {
1977                self.wrap.insert_rule(rule_id, value);
1978            }
1979            Property::GridColumns(columns) => {
1980                self.grid_columns.insert_rule(rule_id, columns);
1981            }
1982
1983            Property::GridRows(rows) => {
1984                self.grid_rows.insert_rule(rule_id, rows);
1985            }
1986
1987            Property::ColumnStart(start) => {
1988                self.column_start.insert_rule(rule_id, start);
1989            }
1990
1991            Property::ColumnSpan(span) => {
1992                self.column_span.insert_rule(rule_id, span);
1993            }
1994
1995            Property::RowStart(start) => {
1996                self.row_start.insert_rule(rule_id, start);
1997            }
1998
1999            Property::RowSpan(span) => {
2000                self.row_span.insert_rule(rule_id, span);
2001            }
2002
2003            // Space
2004            Property::Space(space) => {
2005                self.left.insert_rule(rule_id, space);
2006                self.right.insert_rule(rule_id, space);
2007                self.top.insert_rule(rule_id, space);
2008                self.bottom.insert_rule(rule_id, space);
2009            }
2010
2011            Property::Left(left) => {
2012                self.left.insert_rule(rule_id, left);
2013            }
2014
2015            Property::Right(right) => {
2016                self.right.insert_rule(rule_id, right);
2017            }
2018
2019            Property::Top(top) => {
2020                self.top.insert_rule(rule_id, top);
2021            }
2022
2023            Property::Bottom(bottom) => {
2024                self.bottom.insert_rule(rule_id, bottom);
2025            }
2026
2027            // Size
2028            Property::Size(size) => {
2029                self.width.insert_rule(rule_id, size);
2030                self.height.insert_rule(rule_id, size);
2031            }
2032
2033            Property::Width(width) => {
2034                self.width.insert_rule(rule_id, width);
2035            }
2036
2037            Property::Height(height) => {
2038                self.height.insert_rule(rule_id, height);
2039            }
2040
2041            Property::AspectRatio(aspect_ratio) => {
2042                self.aspect_ratio.insert_rule(rule_id, aspect_ratio);
2043            }
2044
2045            // Padding
2046            Property::Padding(padding) => {
2047                self.padding_left.insert_rule(rule_id, padding);
2048                self.padding_right.insert_rule(rule_id, padding);
2049                self.padding_top.insert_rule(rule_id, padding);
2050                self.padding_bottom.insert_rule(rule_id, padding);
2051            }
2052
2053            Property::PaddingLeft(padding_left) => {
2054                self.padding_left.insert_rule(rule_id, padding_left);
2055            }
2056
2057            Property::PaddingRight(padding_right) => {
2058                self.padding_right.insert_rule(rule_id, padding_right);
2059            }
2060
2061            Property::PaddingTop(padding_top) => {
2062                self.padding_top.insert_rule(rule_id, padding_top);
2063            }
2064
2065            Property::PaddingBottom(padding_bottom) => {
2066                self.padding_bottom.insert_rule(rule_id, padding_bottom);
2067            }
2068
2069            Property::VerticalGap(vertical_gap) => {
2070                self.vertical_gap.insert_rule(rule_id, vertical_gap);
2071            }
2072
2073            Property::HorizontalGap(horizontal_gap) => {
2074                self.horizontal_gap.insert_rule(rule_id, horizontal_gap);
2075            }
2076
2077            Property::Gap(gap) => {
2078                self.horizontal_gap.insert_rule(rule_id, gap);
2079                self.vertical_gap.insert_rule(rule_id, gap);
2080            }
2081
2082            // Size Constraints
2083            Property::MinSize(min_size) => {
2084                self.min_width.insert_rule(rule_id, min_size);
2085                self.min_height.insert_rule(rule_id, min_size);
2086            }
2087
2088            Property::MinWidth(min_width) => {
2089                self.min_width.insert_rule(rule_id, min_width);
2090            }
2091
2092            Property::MinHeight(min_height) => {
2093                self.min_height.insert_rule(rule_id, min_height);
2094            }
2095
2096            Property::MaxSize(max_size) => {
2097                self.max_width.insert_rule(rule_id, max_size);
2098                self.max_height.insert_rule(rule_id, max_size);
2099            }
2100
2101            Property::MaxWidth(max_width) => {
2102                self.max_width.insert_rule(rule_id, max_width);
2103            }
2104
2105            Property::MaxHeight(max_height) => {
2106                self.max_height.insert_rule(rule_id, max_height);
2107            }
2108
2109            // Gap Constraints
2110            Property::MinGap(min_gap) => {
2111                self.min_horizontal_gap.insert_rule(rule_id, min_gap);
2112                self.min_vertical_gap.insert_rule(rule_id, min_gap);
2113            }
2114
2115            Property::MinHorizontalGap(min_gap) => {
2116                self.min_horizontal_gap.insert_rule(rule_id, min_gap);
2117            }
2118
2119            Property::MinVerticalGap(min_gap) => {
2120                self.min_vertical_gap.insert_rule(rule_id, min_gap);
2121            }
2122
2123            Property::MaxGap(max_gap) => {
2124                self.max_horizontal_gap.insert_rule(rule_id, max_gap);
2125                self.max_vertical_gap.insert_rule(rule_id, max_gap);
2126            }
2127
2128            Property::MaxHorizontalGap(max_gap) => {
2129                self.max_horizontal_gap.insert_rule(rule_id, max_gap);
2130            }
2131
2132            Property::MaxVerticalGap(max_gap) => {
2133                self.max_vertical_gap.insert_rule(rule_id, max_gap);
2134            }
2135
2136            // Background Colour
2137            Property::BackgroundColor(color) => {
2138                self.background_color.insert_rule(rule_id, color);
2139            }
2140
2141            // Border
2142            Property::Border(border) => {
2143                if let Some(color) = border.color {
2144                    self.border_top_color.insert_rule(rule_id, color);
2145                    self.border_right_color.insert_rule(rule_id, color);
2146                    self.border_bottom_color.insert_rule(rule_id, color);
2147                    self.border_left_color.insert_rule(rule_id, color);
2148                }
2149
2150                if let Some(width) = border.width {
2151                    let w: LengthOrPercentage = width.into();
2152                    self.border_top_width.insert_rule(rule_id, w.clone());
2153                    self.border_right_width.insert_rule(rule_id, w.clone());
2154                    self.border_bottom_width.insert_rule(rule_id, w.clone());
2155                    self.border_left_width.insert_rule(rule_id, w);
2156                }
2157
2158                if let Some(style) = border.style {
2159                    self.border_top_style.insert_rule(rule_id, style.top);
2160                    self.border_right_style.insert_rule(rule_id, style.right);
2161                    self.border_bottom_style.insert_rule(rule_id, style.bottom);
2162                    self.border_left_style.insert_rule(rule_id, style.left);
2163                }
2164            }
2165
2166            // Border side shorthands
2167            Property::BorderTop(border) => {
2168                if let Some(color) = border.color {
2169                    self.border_top_color.insert_rule(rule_id, color);
2170                }
2171                if let Some(width) = border.width {
2172                    self.border_top_width.insert_rule(rule_id, width.into());
2173                }
2174                if let Some(style) = border.style {
2175                    self.border_top_style.insert_rule(rule_id, style.top);
2176                }
2177            }
2178
2179            Property::BorderRight(border) => {
2180                if let Some(color) = border.color {
2181                    self.border_right_color.insert_rule(rule_id, color);
2182                }
2183                if let Some(width) = border.width {
2184                    self.border_right_width.insert_rule(rule_id, width.into());
2185                }
2186                if let Some(style) = border.style {
2187                    self.border_right_style.insert_rule(rule_id, style.right);
2188                }
2189            }
2190
2191            Property::BorderBottom(border) => {
2192                if let Some(color) = border.color {
2193                    self.border_bottom_color.insert_rule(rule_id, color);
2194                }
2195                if let Some(width) = border.width {
2196                    self.border_bottom_width.insert_rule(rule_id, width.into());
2197                }
2198                if let Some(style) = border.style {
2199                    self.border_bottom_style.insert_rule(rule_id, style.bottom);
2200                }
2201            }
2202
2203            Property::BorderLeft(border) => {
2204                if let Some(color) = border.color {
2205                    self.border_left_color.insert_rule(rule_id, color);
2206                }
2207                if let Some(width) = border.width {
2208                    self.border_left_width.insert_rule(rule_id, width.into());
2209                }
2210                if let Some(style) = border.style {
2211                    self.border_left_style.insert_rule(rule_id, style.left);
2212                }
2213            }
2214
2215            // Border Width
2216            Property::BorderWidth(border_width) => {
2217                self.border_top_width.insert_rule(rule_id, border_width.top.0);
2218                self.border_right_width.insert_rule(rule_id, border_width.right.0);
2219                self.border_bottom_width.insert_rule(rule_id, border_width.bottom.0);
2220                self.border_left_width.insert_rule(rule_id, border_width.left.0);
2221            }
2222
2223            Property::BorderTopWidth(width) => {
2224                self.border_top_width.insert_rule(rule_id, width.into());
2225            }
2226
2227            Property::BorderRightWidth(width) => {
2228                self.border_right_width.insert_rule(rule_id, width.into());
2229            }
2230
2231            Property::BorderBottomWidth(width) => {
2232                self.border_bottom_width.insert_rule(rule_id, width.into());
2233            }
2234
2235            Property::BorderLeftWidth(width) => {
2236                self.border_left_width.insert_rule(rule_id, width.into());
2237            }
2238
2239            // Border Color
2240            Property::BorderColor(color) => {
2241                self.border_top_color.insert_rule(rule_id, color);
2242                self.border_right_color.insert_rule(rule_id, color);
2243                self.border_bottom_color.insert_rule(rule_id, color);
2244                self.border_left_color.insert_rule(rule_id, color);
2245            }
2246
2247            Property::BorderTopColor(color) => {
2248                self.border_top_color.insert_rule(rule_id, color);
2249            }
2250
2251            Property::BorderRightColor(color) => {
2252                self.border_right_color.insert_rule(rule_id, color);
2253            }
2254
2255            Property::BorderBottomColor(color) => {
2256                self.border_bottom_color.insert_rule(rule_id, color);
2257            }
2258
2259            Property::BorderLeftColor(color) => {
2260                self.border_left_color.insert_rule(rule_id, color);
2261            }
2262
2263            // Border Style
2264            Property::BorderStyle(style) => {
2265                self.border_top_style.insert_rule(rule_id, style.top);
2266                self.border_right_style.insert_rule(rule_id, style.right);
2267                self.border_bottom_style.insert_rule(rule_id, style.bottom);
2268                self.border_left_style.insert_rule(rule_id, style.left);
2269            }
2270
2271            Property::BorderTopStyle(style) => {
2272                self.border_top_style.insert_rule(rule_id, style);
2273            }
2274
2275            Property::BorderRightStyle(style) => {
2276                self.border_right_style.insert_rule(rule_id, style);
2277            }
2278
2279            Property::BorderBottomStyle(style) => {
2280                self.border_bottom_style.insert_rule(rule_id, style);
2281            }
2282
2283            Property::BorderLeftStyle(style) => {
2284                self.border_left_style.insert_rule(rule_id, style);
2285            }
2286
2287            // Border Radius
2288            Property::CornerRadius(corner_radius) => {
2289                self.corner_bottom_left_radius.insert_rule(rule_id, corner_radius.bottom_left);
2290                self.corner_bottom_right_radius.insert_rule(rule_id, corner_radius.bottom_right);
2291                self.corner_top_left_radius.insert_rule(rule_id, corner_radius.top_left);
2292                self.corner_top_right_radius.insert_rule(rule_id, corner_radius.top_right);
2293            }
2294
2295            Property::CornerBottomLeftRadius(corner_radius) => {
2296                self.corner_bottom_left_radius.insert_rule(rule_id, corner_radius);
2297            }
2298
2299            Property::CornerTopLeftRadius(corner_radius) => {
2300                self.corner_top_left_radius.insert_rule(rule_id, corner_radius);
2301            }
2302
2303            Property::CornerBottomRightRadius(corner_radius) => {
2304                self.corner_bottom_right_radius.insert_rule(rule_id, corner_radius);
2305            }
2306
2307            Property::CornerTopRightRadius(corner_radius) => {
2308                self.corner_top_right_radius.insert_rule(rule_id, corner_radius);
2309            }
2310
2311            // Font Family
2312            Property::FontFamily(font_family) => {
2313                self.font_family.insert_rule(
2314                    rule_id,
2315                    font_family
2316                        .iter()
2317                        .map(|family| match family {
2318                            FontFamily::Named(name) => FamilyOwned::Named(name.to_string()),
2319                            FontFamily::Generic(generic) => FamilyOwned::Generic(*generic),
2320                        })
2321                        .collect::<Vec<_>>(),
2322                );
2323            }
2324
2325            // Font Color
2326            Property::FontColor(font_color) => {
2327                self.font_color.insert_rule(rule_id, font_color);
2328            }
2329
2330            // Font Size
2331            Property::FontSize(font_size) => {
2332                self.font_size.insert_rule(rule_id, font_size);
2333            }
2334
2335            // Letter Spacing
2336            Property::LetterSpacing(letter_spacing) => {
2337                self.letter_spacing.insert_rule(rule_id, letter_spacing);
2338            }
2339
2340            // Font Weight
2341            Property::FontWeight(font_weight) => {
2342                self.font_weight.insert_rule(rule_id, font_weight);
2343            }
2344
2345            // Font Slant
2346            Property::FontSlant(font_slant) => {
2347                self.font_slant.insert_rule(rule_id, font_slant);
2348            }
2349
2350            // Font Width
2351            Property::FontWidth(font_width) => {
2352                self.font_width.insert_rule(rule_id, font_width);
2353            }
2354
2355            // Font Variation Settings
2356            Property::FontVariationSettings(font_variation_settings) => {
2357                self.font_variation_settings.insert_rule(rule_id, font_variation_settings);
2358            }
2359
2360            // Caret Color
2361            Property::CaretColor(caret_color) => {
2362                self.caret_color.insert_rule(rule_id, caret_color);
2363            }
2364
2365            // Selection Color
2366            Property::SelectionColor(selection_color) => {
2367                self.selection_color.insert_rule(rule_id, selection_color);
2368            }
2369
2370            // Transform
2371            Property::Transform(transforms) => {
2372                self.transform.insert_rule(rule_id, transforms);
2373            }
2374
2375            Property::TransformOrigin(transform_origin) => {
2376                let x = transform_origin.x.to_length_or_percentage();
2377                let y = transform_origin.y.to_length_or_percentage();
2378                self.transform_origin.insert_rule(rule_id, Translate { x, y });
2379            }
2380
2381            Property::Translate(translate) => {
2382                self.translate.insert_rule(rule_id, translate);
2383            }
2384
2385            Property::Rotate(rotate) => {
2386                self.rotate.insert_rule(rule_id, rotate);
2387            }
2388
2389            Property::Scale(scale) => {
2390                self.scale.insert_rule(rule_id, scale);
2391            }
2392
2393            // Overflow
2394            Property::Overflow(overflow) => {
2395                self.overflowx.insert_rule(rule_id, overflow);
2396                self.overflowy.insert_rule(rule_id, overflow);
2397            }
2398
2399            Property::OverflowX(overflow) => {
2400                self.overflowx.insert_rule(rule_id, overflow);
2401            }
2402
2403            Property::OverflowY(overflow) => {
2404                self.overflowy.insert_rule(rule_id, overflow);
2405            }
2406
2407            // Z Index
2408            Property::ZIndex(z_index) => self.z_index.insert_rule(rule_id, z_index),
2409
2410            // Outline
2411            Property::Outline(outline) => {
2412                if let Some(outline_color) = outline.color {
2413                    self.outline_color.insert_rule(rule_id, outline_color);
2414                }
2415
2416                if let Some(outline_width) = outline.width {
2417                    self.outline_width.insert_rule(rule_id, outline_width.into());
2418                }
2419            }
2420
2421            Property::OutlineColor(outline_color) => {
2422                self.outline_color.insert_rule(rule_id, outline_color);
2423            }
2424
2425            Property::OutlineWidth(outline_width) => {
2426                self.outline_width.insert_rule(rule_id, outline_width.left.0);
2427            }
2428
2429            Property::OutlineOffset(outline_offset) => {
2430                self.outline_offset.insert_rule(rule_id, outline_offset);
2431            }
2432
2433            // Background Images & Gradients
2434            Property::BackgroundImage(images) => {
2435                let images = images
2436                    .into_iter()
2437                    .filter_map(|img| match img {
2438                        BackgroundImage::None => None,
2439                        BackgroundImage::Gradient(gradient) => {
2440                            Some(ImageOrGradient::Gradient(*gradient))
2441                        }
2442                        BackgroundImage::Url(url) => {
2443                            Some(ImageOrGradient::Image(url.url.to_string()))
2444                        }
2445                    })
2446                    .collect::<Vec<_>>();
2447
2448                self.background_image.insert_rule(rule_id, images);
2449            }
2450
2451            // Background Position
2452            Property::BackgroundPosition(positions) => {
2453                self.background_position.insert_rule(rule_id, positions);
2454            }
2455
2456            // Background Size
2457            Property::BackgroundSize(sizes) => {
2458                self.background_size.insert_rule(rule_id, sizes);
2459            }
2460
2461            // Background Repeat
2462            Property::BackgroundRepeat(repeats) => {
2463                self.background_repeat.insert_rule(rule_id, repeats);
2464            }
2465
2466            // Text Wrapping
2467            Property::TextWrap(text_wrap) => {
2468                self.text_wrap.insert_rule(rule_id, text_wrap);
2469            }
2470
2471            // Text Alignment
2472            Property::TextAlign(text_align) => {
2473                self.text_align.insert_rule(rule_id, text_align);
2474            }
2475
2476            // Box Shadows
2477            Property::Shadow(shadows) => {
2478                self.shadow.insert_rule(rule_id, shadows);
2479            }
2480
2481            // Cursor Icon
2482            Property::Cursor(cursor) => {
2483                self.cursor.insert_rule(rule_id, cursor);
2484            }
2485
2486            Property::PointerEvents(pointer_events) => {
2487                self.pointer_events.insert_rule(rule_id, pointer_events);
2488            }
2489
2490            Property::TextOverflow(text_overflow) => {
2491                self.text_overflow.insert_rule(rule_id, text_overflow);
2492            }
2493            Property::LineHeight(line_height) => {
2494                self.line_height.insert_rule(rule_id, line_height);
2495            }
2496            Property::LineClamp(line_clamp) => {
2497                self.line_clamp.insert_rule(rule_id, line_clamp);
2498            }
2499            Property::TextDecoration(decoration) => {
2500                self.text_decoration_line.insert_rule(rule_id, decoration.line);
2501                self.text_decoration_style.insert_rule(rule_id, decoration.style);
2502                self.text_decoration_color.insert_rule(rule_id, decoration.color.into());
2503            }
2504            Property::TextDecorationLine(line) => {
2505                self.text_decoration_line.insert_rule(rule_id, line);
2506            }
2507            Property::TextDecorationColor(decoration_color) => {
2508                self.text_decoration_color.insert_rule(rule_id, decoration_color);
2509            }
2510            Property::TextDecorationStyle(decoration_style) => {
2511                self.text_decoration_style.insert_rule(rule_id, decoration_style);
2512            }
2513            Property::TextStroke(stroke) => {
2514                self.text_stroke_width.insert_rule(rule_id, stroke.width);
2515                self.text_stroke_style.insert_rule(rule_id, stroke.style);
2516            }
2517            Property::TextStrokeWidth(stroke_width) => {
2518                self.text_stroke_width.insert_rule(rule_id, stroke_width);
2519            }
2520            Property::TextStrokeStyle(stroke_style) => {
2521                self.text_stroke_style.insert_rule(rule_id, stroke_style);
2522            }
2523            Property::Fill(fill) => {
2524                self.fill.insert_rule(rule_id, fill);
2525            }
2526
2527            // Unparsed. TODO: Log the error.
2528            Property::Unparsed(unparsed) => {
2529                macro_rules! parse_color_var {
2530                    ($($prop:expr),+) => {
2531                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2532                            let hash = variable_hash(var);
2533                            let fallback = color_fallback(var);
2534                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
2535                        }
2536                    };
2537                }
2538                macro_rules! parse_length_var {
2539                    ($($prop:expr),+) => {
2540                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2541                            let hash = variable_hash(var);
2542                            let fallback = length_fallback(var);
2543                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
2544                        }
2545                    };
2546                }
2547                macro_rules! parse_font_size_var {
2548                    ($prop:expr) => {
2549                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2550                            $prop.insert_variable_rule(
2551                                rule_id,
2552                                variable_hash(var),
2553                                font_size_fallback(var),
2554                            );
2555                        }
2556                    };
2557                }
2558                macro_rules! parse_letter_spacing_var {
2559                    ($prop:expr) => {
2560                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2561                            $prop.insert_variable_rule(
2562                                rule_id,
2563                                variable_hash(var),
2564                                letter_spacing_fallback(var),
2565                            );
2566                        }
2567                    };
2568                }
2569                macro_rules! parse_line_height_var {
2570                    ($prop:expr) => {
2571                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2572                            $prop.insert_variable_rule(
2573                                rule_id,
2574                                variable_hash(var),
2575                                line_height_fallback(var),
2576                            );
2577                        }
2578                    };
2579                }
2580                macro_rules! parse_units_var {
2581                    ($($prop:expr),+) => {
2582                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2583                            let hash = variable_hash(var);
2584                            let fallback = units_fallback(var);
2585                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
2586                        }
2587                    };
2588                }
2589                match unparsed.name.as_ref() {
2590                    "background-color" => parse_color_var!(self.background_color),
2591                    "border-color" => parse_color_var!(
2592                        self.border_top_color,
2593                        self.border_right_color,
2594                        self.border_bottom_color,
2595                        self.border_left_color
2596                    ),
2597                    "outline-color" => parse_color_var!(self.outline_color),
2598                    "color" => parse_color_var!(self.font_color),
2599                    "caret-color" => parse_color_var!(self.caret_color),
2600                    "selection-color" => parse_color_var!(self.selection_color),
2601                    "fill" => parse_color_var!(self.fill),
2602                    "text-decoration-color" => parse_color_var!(self.text_decoration_color),
2603                    "font-size" => parse_font_size_var!(self.font_size),
2604                    "letter-spacing" => parse_letter_spacing_var!(self.letter_spacing),
2605                    "line-height" => parse_line_height_var!(self.line_height),
2606                    "corner-radius" => parse_length_var!(
2607                        self.corner_top_left_radius,
2608                        self.corner_top_right_radius,
2609                        self.corner_bottom_left_radius,
2610                        self.corner_bottom_right_radius
2611                    ),
2612                    "corner-top-left-radius" => parse_length_var!(self.corner_top_left_radius),
2613                    "corner-top-right-radius" => parse_length_var!(self.corner_top_right_radius),
2614                    "corner-bottom-left-radius" => {
2615                        parse_length_var!(self.corner_bottom_left_radius)
2616                    }
2617                    "corner-bottom-right-radius" => {
2618                        parse_length_var!(self.corner_bottom_right_radius)
2619                    }
2620                    "border-width" => parse_length_var!(
2621                        self.border_top_width,
2622                        self.border_right_width,
2623                        self.border_bottom_width,
2624                        self.border_left_width
2625                    ),
2626                    "border-top-width" => parse_length_var!(self.border_top_width),
2627                    "border-right-width" => parse_length_var!(self.border_right_width),
2628                    "border-bottom-width" => parse_length_var!(self.border_bottom_width),
2629                    "border-left-width" => parse_length_var!(self.border_left_width),
2630                    "border-top-color" => parse_color_var!(self.border_top_color),
2631                    "border-right-color" => parse_color_var!(self.border_right_color),
2632                    "border-bottom-color" => parse_color_var!(self.border_bottom_color),
2633                    "border-left-color" => parse_color_var!(self.border_left_color),
2634                    "border" => {
2635                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2636                            let hash = variable_hash(var);
2637                            let lf = length_fallback(var);
2638                            let cf = color_fallback(var);
2639                            self.border_top_width.insert_variable_rule(rule_id, hash, lf.clone());
2640                            self.border_right_width.insert_variable_rule(rule_id, hash, lf.clone());
2641                            self.border_bottom_width.insert_variable_rule(
2642                                rule_id,
2643                                hash,
2644                                lf.clone(),
2645                            );
2646                            self.border_left_width.insert_variable_rule(rule_id, hash, lf);
2647                            self.border_top_color.insert_variable_rule(rule_id, hash, cf);
2648                            self.border_right_color.insert_variable_rule(rule_id, hash, cf);
2649                            self.border_bottom_color.insert_variable_rule(rule_id, hash, cf);
2650                            self.border_left_color.insert_variable_rule(rule_id, hash, cf);
2651                        }
2652                    }
2653                    "outline" => {
2654                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2655                            let hash = variable_hash(var);
2656                            self.outline_width.insert_variable_rule(
2657                                rule_id,
2658                                hash,
2659                                length_fallback(var),
2660                            );
2661                            self.outline_color.insert_variable_rule(
2662                                rule_id,
2663                                hash,
2664                                color_fallback(var),
2665                            );
2666                        }
2667                    }
2668                    "outline-width" => parse_length_var!(self.outline_width),
2669                    "outline-offset" => parse_length_var!(self.outline_offset),
2670                    "left" => parse_units_var!(self.left),
2671                    "right" => parse_units_var!(self.right),
2672                    "top" => parse_units_var!(self.top),
2673                    "bottom" => parse_units_var!(self.bottom),
2674                    "space" => parse_units_var!(self.left, self.right, self.top, self.bottom),
2675                    "width" => parse_units_var!(self.width),
2676                    "height" => parse_units_var!(self.height),
2677                    "size" => parse_units_var!(self.width, self.height),
2678                    "min-width" => parse_units_var!(self.min_width),
2679                    "max-width" => parse_units_var!(self.max_width),
2680                    "min-height" => parse_units_var!(self.min_height),
2681                    "max-height" => parse_units_var!(self.max_height),
2682                    "min-size" => parse_units_var!(self.min_width, self.min_height),
2683                    "max-size" => parse_units_var!(self.max_width, self.max_height),
2684                    "padding-left" => parse_units_var!(self.padding_left),
2685                    "padding-right" => parse_units_var!(self.padding_right),
2686                    "padding-top" => parse_units_var!(self.padding_top),
2687                    "padding-bottom" => parse_units_var!(self.padding_bottom),
2688                    "padding" => parse_units_var!(
2689                        self.padding_left,
2690                        self.padding_right,
2691                        self.padding_top,
2692                        self.padding_bottom
2693                    ),
2694                    "row-gap" | "vertical-gap" => parse_units_var!(self.vertical_gap),
2695                    "column-gap" | "horizontal-gap" => parse_units_var!(self.horizontal_gap),
2696                    "gap" => parse_units_var!(self.vertical_gap, self.horizontal_gap),
2697                    "min-gap" => {
2698                        parse_units_var!(self.min_horizontal_gap, self.min_vertical_gap)
2699                    }
2700                    "max-gap" => {
2701                        parse_units_var!(self.max_horizontal_gap, self.max_vertical_gap)
2702                    }
2703                    "opacity" => {
2704                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2705                            self.opacity.insert_variable_rule(
2706                                rule_id,
2707                                variable_hash(var),
2708                                opacity_fallback(var),
2709                            );
2710                        }
2711                    }
2712                    "shadow" => {
2713                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2714                            self.shadow.insert_variable_rule(
2715                                rule_id,
2716                                variable_hash(var),
2717                                shadow_fallback(var),
2718                            );
2719                        }
2720                    }
2721                    n => warn!("Unparsed {} {:?}", n, unparsed.value),
2722                }
2723            }
2724
2725            Property::Custom(custom) => {
2726                let mut s = DefaultHasher::new();
2727                custom.name.hash(&mut s);
2728                let variable_name_hash = s.finish();
2729
2730                if let Some(shadows) = parse_shadow_list(&custom.value.0) {
2731                    if let Some(store) = self.custom_shadow_props.get_mut(&variable_name_hash) {
2732                        store.insert_rule(rule_id, shadows);
2733                    } else {
2734                        let mut store = AnimatableVarSet::default();
2735                        store.insert_rule(rule_id, shadows);
2736                        self.custom_shadow_props.insert(variable_name_hash, store);
2737                    }
2738                }
2739
2740                // Parse custom properties and store them
2741                for token in custom.value.0.iter() {
2742                    // Try parsing colors
2743                    if let TokenOrValue::Color(color) = token {
2744                        if let Some(store) = self.custom_color_props.get_mut(&variable_name_hash) {
2745                            store.insert_rule(rule_id, *color);
2746                        } else {
2747                            let mut store = AnimatableVarSet::default();
2748                            store.insert_rule(rule_id, *color);
2749                            self.custom_color_props.insert(variable_name_hash, store);
2750                        }
2751                    }
2752
2753                    // Parse length/percentage tokens into custom_length_props
2754                    match token {
2755                        TokenOrValue::Token(CssToken::Dimension { value, unit, .. }) => {
2756                            let lop = if unit.as_ref().eq_ignore_ascii_case("px") {
2757                                Some(LengthOrPercentage::Length(Length::Value(LengthValue::Px(
2758                                    *value,
2759                                ))))
2760                            } else {
2761                                None
2762                            };
2763                            if let Some(lop) = lop {
2764                                if let Some(store) =
2765                                    self.custom_length_props.get_mut(&variable_name_hash)
2766                                {
2767                                    store.insert_rule(rule_id, lop.clone());
2768                                } else {
2769                                    let mut store = AnimatableVarSet::default();
2770                                    store.insert_rule(rule_id, lop.clone());
2771                                    self.custom_length_props.insert(variable_name_hash, store);
2772                                }
2773                                // Also try storing as FontSize
2774                                let fs = FontSize(Length::Value(LengthValue::Px(*value)));
2775                                if let Some(store) =
2776                                    self.custom_font_size_props.get_mut(&variable_name_hash)
2777                                {
2778                                    store.insert_rule(rule_id, fs);
2779                                } else {
2780                                    let mut store = AnimatableVarSet::default();
2781                                    store.insert_rule(rule_id, fs);
2782                                    self.custom_font_size_props.insert(variable_name_hash, store);
2783                                }
2784                                // Also try storing as LetterSpacing::Length
2785                                let letter_spacing =
2786                                    LetterSpacing::Length(Length::Value(LengthValue::Px(*value)));
2787                                if let Some(store) =
2788                                    self.custom_letter_spacing_props.get_mut(&variable_name_hash)
2789                                {
2790                                    store.insert_rule(rule_id, letter_spacing);
2791                                } else {
2792                                    let mut store = AnimatableVarSet::default();
2793                                    store.insert_rule(rule_id, letter_spacing);
2794                                    self.custom_letter_spacing_props
2795                                        .insert(variable_name_hash, store);
2796                                }
2797                                // Also try storing as LineHeight::Length
2798                                let line_height =
2799                                    LineHeight::Length(Length::Value(LengthValue::Px(*value)));
2800                                if let Some(store) =
2801                                    self.custom_line_height_props.get_mut(&variable_name_hash)
2802                                {
2803                                    store.insert_rule(rule_id, line_height);
2804                                } else {
2805                                    let mut store = AnimatableVarSet::default();
2806                                    store.insert_rule(rule_id, line_height);
2807                                    self.custom_line_height_props.insert(variable_name_hash, store);
2808                                }
2809                                // Also store as Units::Pixels
2810                                let units_val = Units::Pixels(*value);
2811                                if let Some(store) =
2812                                    self.custom_units_props.get_mut(&variable_name_hash)
2813                                {
2814                                    store.insert_rule(rule_id, units_val);
2815                                } else {
2816                                    let mut store = AnimatableVarSet::default();
2817                                    store.insert_rule(rule_id, units_val);
2818                                    self.custom_units_props.insert(variable_name_hash, store);
2819                                }
2820                            } else if unit.as_ref().eq_ignore_ascii_case("s") {
2821                                // "1s" => Units::Stretch(1.0)
2822                                let units_val = Units::Stretch(*value);
2823                                if let Some(store) =
2824                                    self.custom_units_props.get_mut(&variable_name_hash)
2825                                {
2826                                    store.insert_rule(rule_id, units_val);
2827                                } else {
2828                                    let mut store = AnimatableVarSet::default();
2829                                    store.insert_rule(rule_id, units_val);
2830                                    self.custom_units_props.insert(variable_name_hash, store);
2831                                }
2832                            }
2833                        }
2834                        TokenOrValue::Token(CssToken::Ident(ident))
2835                            if ident.as_ref().eq_ignore_ascii_case("auto") =>
2836                        {
2837                            let units_val = Units::Auto;
2838                            if let Some(store) =
2839                                self.custom_units_props.get_mut(&variable_name_hash)
2840                            {
2841                                store.insert_rule(rule_id, units_val);
2842                            } else {
2843                                let mut store = AnimatableVarSet::default();
2844                                store.insert_rule(rule_id, units_val);
2845                                self.custom_units_props.insert(variable_name_hash, store);
2846                            }
2847                        }
2848                        TokenOrValue::Token(CssToken::Percentage { unit_value, .. }) => {
2849                            let lop = LengthOrPercentage::Percentage(*unit_value * 100.0);
2850                            if let Some(store) =
2851                                self.custom_length_props.get_mut(&variable_name_hash)
2852                            {
2853                                store.insert_rule(rule_id, lop);
2854                            } else {
2855                                let mut store = AnimatableVarSet::default();
2856                                store.insert_rule(rule_id, lop);
2857                                self.custom_length_props.insert(variable_name_hash, store);
2858                            }
2859                            // Also store as LineHeight::Percentage
2860                            let line_height = LineHeight::Percentage(*unit_value * 100.0);
2861                            if let Some(store) =
2862                                self.custom_line_height_props.get_mut(&variable_name_hash)
2863                            {
2864                                store.insert_rule(rule_id, line_height);
2865                            } else {
2866                                let mut store = AnimatableVarSet::default();
2867                                store.insert_rule(rule_id, line_height);
2868                                self.custom_line_height_props.insert(variable_name_hash, store);
2869                            }
2870                            // Also store as Units::Percentage
2871                            let units_val = Units::Percentage(*unit_value * 100.0);
2872                            if let Some(store) =
2873                                self.custom_units_props.get_mut(&variable_name_hash)
2874                            {
2875                                store.insert_rule(rule_id, units_val);
2876                            } else {
2877                                let mut store = AnimatableVarSet::default();
2878                                store.insert_rule(rule_id, units_val);
2879                                self.custom_units_props.insert(variable_name_hash, store);
2880                            }
2881                            // Also store as Opacity (percentage as 0..1)
2882                            let opacity_val = Opacity(*unit_value);
2883                            if let Some(store) =
2884                                self.custom_opacity_props.get_mut(&variable_name_hash)
2885                            {
2886                                store.insert_rule(rule_id, opacity_val);
2887                            } else {
2888                                let mut store = AnimatableVarSet::default();
2889                                store.insert_rule(rule_id, opacity_val);
2890                                self.custom_opacity_props.insert(variable_name_hash, store);
2891                            }
2892                        }
2893                        TokenOrValue::Var(var) => {
2894                            let name_hash = variable_hash(var);
2895                            // Store var reference in all maps (type is unknown at parse time)
2896                            if let Some(store) =
2897                                self.custom_color_props.get_mut(&variable_name_hash)
2898                            {
2899                                store.insert_variable_rule(rule_id, name_hash, color_fallback(var));
2900                            } else {
2901                                let mut store = AnimatableVarSet::default();
2902                                store.insert_variable_rule(rule_id, name_hash, color_fallback(var));
2903                                self.custom_color_props.insert(variable_name_hash, store);
2904                            }
2905                            if let Some(store) =
2906                                self.custom_length_props.get_mut(&variable_name_hash)
2907                            {
2908                                store.insert_variable_rule(
2909                                    rule_id,
2910                                    name_hash,
2911                                    length_fallback(var),
2912                                );
2913                            } else {
2914                                let mut store: AnimatableVarSet<LengthOrPercentage> =
2915                                    AnimatableVarSet::default();
2916                                store.insert_variable_rule(
2917                                    rule_id,
2918                                    name_hash,
2919                                    length_fallback(var),
2920                                );
2921                                self.custom_length_props.insert(variable_name_hash, store);
2922                            }
2923                            if let Some(store) =
2924                                self.custom_font_size_props.get_mut(&variable_name_hash)
2925                            {
2926                                store.insert_variable_rule(
2927                                    rule_id,
2928                                    name_hash,
2929                                    font_size_fallback(var),
2930                                );
2931                            } else {
2932                                let mut store: AnimatableVarSet<FontSize> =
2933                                    AnimatableVarSet::default();
2934                                store.insert_variable_rule(
2935                                    rule_id,
2936                                    name_hash,
2937                                    font_size_fallback(var),
2938                                );
2939                                self.custom_font_size_props.insert(variable_name_hash, store);
2940                            }
2941                            if let Some(store) =
2942                                self.custom_letter_spacing_props.get_mut(&variable_name_hash)
2943                            {
2944                                store.insert_variable_rule(
2945                                    rule_id,
2946                                    name_hash,
2947                                    letter_spacing_fallback(var),
2948                                );
2949                            } else {
2950                                let mut store: AnimatableVarSet<LetterSpacing> =
2951                                    AnimatableVarSet::default();
2952                                store.insert_variable_rule(
2953                                    rule_id,
2954                                    name_hash,
2955                                    letter_spacing_fallback(var),
2956                                );
2957                                self.custom_letter_spacing_props.insert(variable_name_hash, store);
2958                            }
2959                            if let Some(store) =
2960                                self.custom_line_height_props.get_mut(&variable_name_hash)
2961                            {
2962                                store.insert_variable_rule(
2963                                    rule_id,
2964                                    name_hash,
2965                                    line_height_fallback(var),
2966                                );
2967                            } else {
2968                                let mut store: AnimatableVarSet<LineHeight> =
2969                                    AnimatableVarSet::default();
2970                                store.insert_variable_rule(
2971                                    rule_id,
2972                                    name_hash,
2973                                    line_height_fallback(var),
2974                                );
2975                                self.custom_line_height_props.insert(variable_name_hash, store);
2976                            }
2977                            if let Some(store) =
2978                                self.custom_units_props.get_mut(&variable_name_hash)
2979                            {
2980                                store.insert_variable_rule(rule_id, name_hash, units_fallback(var));
2981                            } else {
2982                                let mut store: AnimatableVarSet<Units> =
2983                                    AnimatableVarSet::default();
2984                                store.insert_variable_rule(rule_id, name_hash, units_fallback(var));
2985                                self.custom_units_props.insert(variable_name_hash, store);
2986                            }
2987                            if let Some(store) =
2988                                self.custom_opacity_props.get_mut(&variable_name_hash)
2989                            {
2990                                store.insert_variable_rule(
2991                                    rule_id,
2992                                    name_hash,
2993                                    opacity_fallback(var),
2994                                );
2995                            } else {
2996                                let mut store: AnimatableVarSet<Opacity> =
2997                                    AnimatableVarSet::default();
2998                                store.insert_variable_rule(
2999                                    rule_id,
3000                                    name_hash,
3001                                    opacity_fallback(var),
3002                                );
3003                                self.custom_opacity_props.insert(variable_name_hash, store);
3004                            }
3005
3006                            if let Some(store) =
3007                                self.custom_shadow_props.get_mut(&variable_name_hash)
3008                            {
3009                                store.insert_variable_rule(
3010                                    rule_id,
3011                                    name_hash,
3012                                    shadow_fallback(var),
3013                                );
3014                            } else {
3015                                let mut store: AnimatableVarSet<Vec<Shadow>> =
3016                                    AnimatableVarSet::default();
3017                                store.insert_variable_rule(
3018                                    rule_id,
3019                                    name_hash,
3020                                    shadow_fallback(var),
3021                                );
3022                                self.custom_shadow_props.insert(variable_name_hash, store);
3023                            }
3024                        }
3025                        TokenOrValue::Token(CssToken::Number { value, .. }) => {
3026                            // Plain number like 0.5 → Opacity
3027                            let opacity_val = Opacity(*value);
3028                            if let Some(store) =
3029                                self.custom_opacity_props.get_mut(&variable_name_hash)
3030                            {
3031                                store.insert_rule(rule_id, opacity_val);
3032                            } else {
3033                                let mut store = AnimatableVarSet::default();
3034                                store.insert_rule(rule_id, opacity_val);
3035                                self.custom_opacity_props.insert(variable_name_hash, store);
3036                            }
3037
3038                            // Plain number like 1.2 -> LineHeight::Number
3039                            let line_height = LineHeight::Number(*value);
3040                            if let Some(store) =
3041                                self.custom_line_height_props.get_mut(&variable_name_hash)
3042                            {
3043                                store.insert_rule(rule_id, line_height);
3044                            } else {
3045                                let mut store = AnimatableVarSet::default();
3046                                store.insert_rule(rule_id, line_height);
3047                                self.custom_line_height_props.insert(variable_name_hash, store);
3048                            }
3049                        }
3050                        TokenOrValue::Token(CssToken::Ident(ident))
3051                            if ident.as_ref().eq_ignore_ascii_case("normal") =>
3052                        {
3053                            let line_height = LineHeight::Normal;
3054                            if let Some(store) =
3055                                self.custom_line_height_props.get_mut(&variable_name_hash)
3056                            {
3057                                store.insert_rule(rule_id, line_height);
3058                            } else {
3059                                let mut store = AnimatableVarSet::default();
3060                                store.insert_rule(rule_id, line_height);
3061                                self.custom_line_height_props.insert(variable_name_hash, store);
3062                            }
3063
3064                            let letter_spacing = LetterSpacing::Normal;
3065                            if let Some(store) =
3066                                self.custom_letter_spacing_props.get_mut(&variable_name_hash)
3067                            {
3068                                store.insert_rule(rule_id, letter_spacing);
3069                            } else {
3070                                let mut store = AnimatableVarSet::default();
3071                                store.insert_rule(rule_id, letter_spacing);
3072                                self.custom_letter_spacing_props.insert(variable_name_hash, store);
3073                            }
3074                        }
3075                        _ => {}
3076                    }
3077                }
3078            }
3079            _ => {}
3080        }
3081    }
3082
3083    // Helper function for generating AnimationState from a transition definition.
3084    fn add_transition<T: Default + Interpolator>(
3085        &self,
3086        transition: &Transition,
3087    ) -> AnimationState<T> {
3088        let timing_function = transition
3089            .timing_function
3090            .map(|easing| match easing {
3091                EasingFunction::Linear => TimingFunction::linear(),
3092                EasingFunction::Ease => TimingFunction::ease(),
3093                EasingFunction::EaseIn => TimingFunction::ease_in(),
3094                EasingFunction::EaseOut => TimingFunction::ease_out(),
3095                EasingFunction::EaseInOut => TimingFunction::ease_in_out(),
3096                EasingFunction::CubicBezier(x1, y1, x2, y2) => TimingFunction::new(x1, y1, x2, y2),
3097            })
3098            .unwrap_or_default();
3099
3100        AnimationState::new(Animation::null())
3101            .with_duration(transition.duration)
3102            .with_delay(transition.delay.unwrap_or_default())
3103            .with_keyframe(Keyframe { time: 0.0, value: Default::default(), timing_function })
3104            .with_keyframe(Keyframe { time: 1.0, value: Default::default(), timing_function })
3105    }
3106
3107    // Add style data for the given entity.
3108    pub(crate) fn add(&mut self, entity: Entity) {
3109        self.pseudo_classes.insert(entity, PseudoClassFlags::VALID);
3110        self.classes.insert(entity, HashSet::new());
3111        self.abilities.insert(entity, Abilities::default());
3112        self.system_flags = SystemFlags::RELAYOUT;
3113        // Adding an entity is a structural change. Relayout incrementally from the new entity;
3114        // morphorm restarts from at least its parent, which repositions all of the parent's
3115        // children. Marking the root here would force a full tree relayout on every view creation.
3116        self.relayout.insert(entity);
3117        self.restyle.insert(entity);
3118        self.reaccess.insert(entity);
3119        self.retransform.insert(entity);
3120        self.reclip.insert(entity);
3121    }
3122
3123    // Remove style data for the given entity.
3124    pub(crate) fn remove(&mut self, entity: Entity) {
3125        self.relayout.remove(&entity);
3126        self.laid_out.remove(&entity);
3127        self.ids.remove(entity);
3128        self.classes.remove(entity);
3129        self.pseudo_classes.remove(entity);
3130        self.disabled.remove(entity);
3131        self.abilities.remove(entity);
3132
3133        self.name.remove(entity);
3134        self.role.remove(entity);
3135        // self.default_action_verb.remove(entity);
3136        self.live.remove(entity);
3137        self.labelled_by.remove(entity);
3138        self.described_by.remove(entity);
3139        self.controls.remove(entity);
3140        self.active_descendant.remove(entity);
3141        self.expanded.remove(entity);
3142        self.selected.remove(entity);
3143        self.multiselectable.remove(entity);
3144        self.sort_direction.remove(entity);
3145        self.level.remove(entity);
3146        self.size_of_set.remove(entity);
3147        self.position_in_set.remove(entity);
3148        self.hidden.remove(entity);
3149        self.orientation.remove(entity);
3150        self.text_value.remove(entity);
3151        self.numeric_value.remove(entity);
3152
3153        // Display
3154        self.display.remove(entity);
3155        // Visibility
3156        self.visibility.remove(entity);
3157        // Opacity
3158        self.opacity.remove(entity);
3159        // Z Order
3160        self.z_index.remove(entity);
3161        self.ignore_clipping.remove(entity);
3162        // Clipping
3163        self.clip_path.remove(entity);
3164
3165        self.overflowx.remove(entity);
3166        self.overflowy.remove(entity);
3167
3168        // Filters
3169        self.filter.remove(entity);
3170        self.backdrop_filter.remove(entity);
3171
3172        // Blend Mode
3173        self.blend_mode.remove(entity);
3174
3175        // Transform
3176        self.transform.remove(entity);
3177        self.transform_origin.remove(entity);
3178        self.translate.remove(entity);
3179        self.rotate.remove(entity);
3180        self.scale.remove(entity);
3181
3182        // Border widths
3183        self.border_top_width.remove(entity);
3184        self.border_right_width.remove(entity);
3185        self.border_bottom_width.remove(entity);
3186        self.border_left_width.remove(entity);
3187        // Border colors
3188        self.border_top_color.remove(entity);
3189        self.border_right_color.remove(entity);
3190        self.border_bottom_color.remove(entity);
3191        self.border_left_color.remove(entity);
3192        // Border styles
3193        self.border_top_style.remove(entity);
3194        self.border_right_style.remove(entity);
3195        self.border_bottom_style.remove(entity);
3196        self.border_left_style.remove(entity);
3197
3198        // Corner Radius
3199        self.corner_bottom_left_radius.remove(entity);
3200        self.corner_bottom_right_radius.remove(entity);
3201        self.corner_top_left_radius.remove(entity);
3202        self.corner_top_right_radius.remove(entity);
3203
3204        // Outline
3205        self.outline_width.remove(entity);
3206        self.outline_color.remove(entity);
3207        self.outline_offset.remove(entity);
3208
3209        // Background
3210        self.background_color.remove(entity);
3211        self.background_image.remove(entity);
3212        self.background_position.remove(entity);
3213        self.background_repeat.remove(entity);
3214        self.background_size.remove(entity);
3215
3216        // Box Shadow
3217        self.shadow.remove(entity);
3218
3219        // Text and Font
3220        self.text.remove(entity);
3221        self.text_wrap.remove(entity);
3222        self.text_overflow.remove(entity);
3223        self.letter_spacing.remove(entity);
3224        self.line_height.remove(entity);
3225        self.line_clamp.remove(entity);
3226        self.text_align.remove(entity);
3227        self.font_family.remove(entity);
3228        self.font_color.remove(entity);
3229        self.font_size.remove(entity);
3230        self.font_weight.remove(entity);
3231        self.font_slant.remove(entity);
3232        self.font_width.remove(entity);
3233        self.font_variation_settings.remove(entity);
3234        self.caret_color.remove(entity);
3235        self.selection_color.remove(entity);
3236        self.text_decoration_line.remove(entity);
3237        self.text_decoration_style.remove(entity);
3238        self.text_decoration_color.remove(entity);
3239        self.text_stroke_width.remove(entity);
3240        self.text_stroke_style.remove(entity);
3241
3242        // Cursor
3243        self.cursor.remove(entity);
3244
3245        self.pointer_events.remove(entity);
3246
3247        // Layout Type
3248        self.layout_type.remove(entity);
3249
3250        // Position Type
3251        self.position_type.remove(entity);
3252
3253        self.alignment.remove(entity);
3254        self.direction.remove(entity);
3255        self.wrap.remove(entity);
3256
3257        // Grid
3258        self.grid_columns.remove(entity);
3259        self.grid_rows.remove(entity);
3260        self.column_start.remove(entity);
3261        self.column_span.remove(entity);
3262        self.row_start.remove(entity);
3263        self.row_span.remove(entity);
3264
3265        // Space
3266        self.left.remove(entity);
3267        self.right.remove(entity);
3268        self.top.remove(entity);
3269        self.bottom.remove(entity);
3270
3271        // Padding
3272        self.padding_left.remove(entity);
3273        self.padding_right.remove(entity);
3274        self.padding_top.remove(entity);
3275        self.padding_bottom.remove(entity);
3276        self.vertical_gap.remove(entity);
3277        self.horizontal_gap.remove(entity);
3278
3279        // Size
3280        self.width.remove(entity);
3281        self.height.remove(entity);
3282        self.aspect_ratio.remove(entity);
3283
3284        // Size Constraints
3285        self.min_width.remove(entity);
3286        self.max_width.remove(entity);
3287        self.min_height.remove(entity);
3288        self.max_height.remove(entity);
3289
3290        self.min_horizontal_gap.remove(entity);
3291        self.max_horizontal_gap.remove(entity);
3292        self.min_vertical_gap.remove(entity);
3293        self.max_vertical_gap.remove(entity);
3294
3295        self.text_range.remove(entity);
3296        self.text_span.remove(entity);
3297
3298        self.fill.remove(entity);
3299
3300        // Remove per-entity data from custom property stores
3301        for store in self.custom_color_props.values_mut() {
3302            store.remove(entity);
3303        }
3304        for store in self.custom_length_props.values_mut() {
3305            store.remove(entity);
3306        }
3307        for store in self.custom_font_size_props.values_mut() {
3308            store.remove(entity);
3309        }
3310        for store in self.custom_letter_spacing_props.values_mut() {
3311            store.remove(entity);
3312        }
3313        for store in self.custom_line_height_props.values_mut() {
3314            store.remove(entity);
3315        }
3316        for store in self.custom_units_props.values_mut() {
3317            store.remove(entity);
3318        }
3319        for store in self.custom_opacity_props.values_mut() {
3320            store.remove(entity);
3321        }
3322    }
3323
3324    pub(crate) fn needs_restyle(&mut self, entity: Entity) {
3325        if entity == Entity::null() || self.restyle.contains(&entity) {
3326            return;
3327        }
3328        self.restyle.insert(entity);
3329    }
3330
3331    pub(crate) fn needs_relayout(&mut self, entity: Entity) {
3332        self.relayout.insert(entity);
3333    }
3334
3335    pub(crate) fn needs_access_update(&mut self, entity: Entity) {
3336        self.reaccess.insert(entity);
3337    }
3338
3339    pub(crate) fn needs_text_update(&mut self, entity: Entity) {
3340        self.text_construction.insert(entity);
3341        self.text_layout.insert(entity);
3342    }
3343
3344    pub(crate) fn needs_text_layout(&mut self, entity: Entity) {
3345        self.text_layout.insert(entity);
3346    }
3347
3348    pub(crate) fn needs_retransform(&mut self, entity: Entity) {
3349        self.retransform.insert(entity);
3350    }
3351
3352    pub(crate) fn needs_reclip(&mut self, entity: Entity) {
3353        self.reclip.insert(entity);
3354    }
3355
3356    // pub fn should_redraw<F: FnOnce()>(&mut self, f: F) {
3357    //     if !self.redraw_list.is_empty() {
3358    //         f();
3359    //     }
3360    // }
3361
3362    // Remove all shared style data.
3363    pub(crate) fn clear_style_rules(&mut self) {
3364        self.disabled.clear_rules();
3365        // Display
3366        self.display.clear_rules();
3367        // Visibility
3368        self.visibility.clear_rules();
3369        // Opacity
3370        self.opacity.clear_rules();
3371        // Z Order
3372        self.z_index.clear_rules();
3373
3374        // Clipping
3375        self.clip_path.clear_rules();
3376
3377        // Filters
3378        self.filter.clear_rules();
3379        self.backdrop_filter.clear_rules();
3380
3381        // Blend Mode
3382        self.blend_mode.clear_rules();
3383
3384        // Transform
3385        self.transform.clear_rules();
3386        self.transform_origin.clear_rules();
3387        self.translate.clear_rules();
3388        self.rotate.clear_rules();
3389        self.scale.clear_rules();
3390
3391        self.overflowx.clear_rules();
3392        self.overflowy.clear_rules();
3393
3394        // Border widths
3395        self.border_top_width.clear_rules();
3396        self.border_right_width.clear_rules();
3397        self.border_bottom_width.clear_rules();
3398        self.border_left_width.clear_rules();
3399        // Border colors
3400        self.border_top_color.clear_rules();
3401        self.border_right_color.clear_rules();
3402        self.border_bottom_color.clear_rules();
3403        self.border_left_color.clear_rules();
3404        // Border styles
3405        self.border_top_style.clear_rules();
3406        self.border_right_style.clear_rules();
3407        self.border_bottom_style.clear_rules();
3408        self.border_left_style.clear_rules();
3409
3410        // Corner Radius
3411        self.corner_bottom_left_radius.clear_rules();
3412        self.corner_bottom_right_radius.clear_rules();
3413        self.corner_top_left_radius.clear_rules();
3414        self.corner_top_right_radius.clear_rules();
3415
3416        // Outline
3417        self.outline_width.clear_rules();
3418        self.outline_color.clear_rules();
3419        self.outline_offset.clear_rules();
3420
3421        // Background
3422        self.background_color.clear_rules();
3423        self.background_image.clear_rules();
3424        self.background_position.clear_rules();
3425        self.background_repeat.clear_rules();
3426        self.background_size.clear_rules();
3427
3428        self.shadow.clear_rules();
3429
3430        self.layout_type.clear_rules();
3431        self.position_type.clear_rules();
3432        self.alignment.clear_rules();
3433        self.direction.clear_rules();
3434        self.wrap.clear_rules();
3435
3436        // Grid
3437        self.grid_columns.clear_rules();
3438        self.grid_rows.clear_rules();
3439        self.column_start.clear_rules();
3440        self.column_span.clear_rules();
3441
3442        // Space
3443        self.left.clear_rules();
3444        self.right.clear_rules();
3445        self.top.clear_rules();
3446        self.bottom.clear_rules();
3447
3448        // Size
3449        self.width.clear_rules();
3450        self.height.clear_rules();
3451
3452        // Size Constraints
3453        self.min_width.clear_rules();
3454        self.max_width.clear_rules();
3455        self.min_height.clear_rules();
3456        self.max_height.clear_rules();
3457
3458        self.min_horizontal_gap.clear_rules();
3459        self.max_horizontal_gap.clear_rules();
3460        self.min_vertical_gap.clear_rules();
3461        self.max_vertical_gap.clear_rules();
3462
3463        // Padding
3464        self.padding_left.clear_rules();
3465        self.padding_right.clear_rules();
3466        self.padding_top.clear_rules();
3467        self.padding_bottom.clear_rules();
3468        self.horizontal_gap.clear_rules();
3469        self.vertical_gap.clear_rules();
3470
3471        // Text and Font
3472        self.text_wrap.clear_rules();
3473        self.text_overflow.clear_rules();
3474        self.letter_spacing.clear_rules();
3475        self.line_height.clear_rules();
3476        self.line_clamp.clear_rules();
3477        self.text_align.clear_rules();
3478        self.font_family.clear_rules();
3479        self.font_weight.clear_rules();
3480        self.font_slant.clear_rules();
3481        self.font_color.clear_rules();
3482        self.font_size.clear_rules();
3483        self.font_variation_settings.clear_rules();
3484        self.selection_color.clear_rules();
3485        self.caret_color.clear_rules();
3486        self.text_decoration_line.clear_rules();
3487        self.text_decoration_style.clear_rules();
3488        self.text_decoration_color.clear_rules();
3489        self.text_stroke_width.clear_rules();
3490        self.text_stroke_style.clear_rules();
3491
3492        self.cursor.clear_rules();
3493
3494        self.pointer_events.clear_rules();
3495
3496        self.name.clear_rules();
3497
3498        self.fill.clear_rules();
3499
3500        // Clear all custom property rule data on stylesheet reload
3501        for store in self.custom_color_props.values_mut() {
3502            store.clear_rules();
3503        }
3504        self.custom_color_props
3505            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3506        for store in self.custom_length_props.values_mut() {
3507            store.clear_rules();
3508        }
3509        self.custom_length_props
3510            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3511        for store in self.custom_font_size_props.values_mut() {
3512            store.clear_rules();
3513        }
3514        self.custom_font_size_props
3515            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3516        for store in self.custom_letter_spacing_props.values_mut() {
3517            store.clear_rules();
3518        }
3519        self.custom_letter_spacing_props
3520            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3521        for store in self.custom_line_height_props.values_mut() {
3522            store.clear_rules();
3523        }
3524        self.custom_line_height_props
3525            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3526        for store in self.custom_units_props.values_mut() {
3527            store.clear_rules();
3528        }
3529        self.custom_units_props
3530            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3531        for store in self.custom_opacity_props.values_mut() {
3532            store.clear_rules();
3533        }
3534        self.custom_opacity_props
3535            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3536    }
3537}