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