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                            if let Some(length) = parse_shadow_length(other) {
1890                                lengths.push(length);
1891                            } else {
1892                                return None;
1893                            }
1894                        }
1895                    }
1896                }
1897
1898                if !(2..=4).contains(&lengths.len()) {
1899                    return None;
1900                }
1901
1902                let x_offset = lengths[0].clone();
1903                let y_offset = lengths[1].clone();
1904                let blur_radius = lengths.get(2).cloned();
1905                let spread_radius = lengths.get(3).cloned();
1906
1907                Some(Shadow::new(x_offset, y_offset, blur_radius, spread_radius, color, inset))
1908            }
1909
1910            let mut parts = Vec::<&[TokenOrValue<'_>]>::new();
1911            let mut start = 0usize;
1912            for (idx, token) in tokens.iter().enumerate() {
1913                if matches!(token, TokenOrValue::Token(CssToken::Comma)) {
1914                    parts.push(&tokens[start..idx]);
1915                    start = idx + 1;
1916                }
1917            }
1918            parts.push(&tokens[start..]);
1919
1920            let mut parsed = Vec::new();
1921            for part in parts {
1922                let shadow = parse_single_shadow(part)?;
1923                parsed.push(shadow);
1924            }
1925
1926            Some(parsed)
1927        }
1928
1929        fn shadow_fallback(var: &Variable<'_>) -> Option<Vec<Shadow>> {
1930            var.fallback.as_ref().and_then(|TokenList(tokens)| parse_shadow_list(tokens))
1931        }
1932
1933        match property.clone() {
1934            // Display
1935            Property::Display(display) => {
1936                self.display.insert_rule(rule_id, display);
1937            }
1938
1939            // Visibility
1940            Property::Visibility(visibility) => {
1941                self.visibility.insert_rule(rule_id, visibility);
1942            }
1943
1944            // Opacity
1945            Property::Opacity(opacity) => {
1946                self.opacity.insert_rule(rule_id, opacity);
1947            }
1948
1949            // Clipping
1950            Property::ClipPath(clip) => {
1951                self.clip_path.insert_rule(rule_id, clip);
1952            }
1953
1954            // Filters
1955            Property::Filter(filter) => {
1956                self.filter.insert_rule(rule_id, filter);
1957            }
1958
1959            Property::BackdropFilter(filter) => {
1960                self.backdrop_filter.insert_rule(rule_id, filter);
1961            }
1962
1963            // Blend Mode
1964            Property::BlendMode(blend_mode) => {
1965                self.blend_mode.insert_rule(rule_id, blend_mode);
1966            }
1967
1968            // Layout Type
1969            Property::LayoutType(layout_type) => {
1970                self.layout_type.insert_rule(rule_id, layout_type);
1971            }
1972
1973            // Position Type
1974            Property::PositionType(position) => {
1975                self.position_type.insert_rule(rule_id, position);
1976            }
1977
1978            Property::Alignment(alignment) => {
1979                self.alignment.insert_rule(rule_id, alignment);
1980            }
1981
1982            Property::Direction(direction) => {
1983                self.direction.insert_rule(rule_id, direction);
1984            }
1985
1986            Property::Wrap(value) => {
1987                self.wrap.insert_rule(rule_id, value);
1988            }
1989            Property::GridColumns(columns) => {
1990                self.grid_columns.insert_rule(rule_id, columns);
1991            }
1992
1993            Property::GridRows(rows) => {
1994                self.grid_rows.insert_rule(rule_id, rows);
1995            }
1996
1997            Property::ColumnStart(start) => {
1998                self.column_start.insert_rule(rule_id, start);
1999            }
2000
2001            Property::ColumnSpan(span) => {
2002                self.column_span.insert_rule(rule_id, span);
2003            }
2004
2005            Property::RowStart(start) => {
2006                self.row_start.insert_rule(rule_id, start);
2007            }
2008
2009            Property::RowSpan(span) => {
2010                self.row_span.insert_rule(rule_id, span);
2011            }
2012
2013            // Space
2014            Property::Space(space) => {
2015                self.left.insert_rule(rule_id, space);
2016                self.right.insert_rule(rule_id, space);
2017                self.top.insert_rule(rule_id, space);
2018                self.bottom.insert_rule(rule_id, space);
2019            }
2020
2021            Property::Left(left) => {
2022                self.left.insert_rule(rule_id, left);
2023            }
2024
2025            Property::Right(right) => {
2026                self.right.insert_rule(rule_id, right);
2027            }
2028
2029            Property::Top(top) => {
2030                self.top.insert_rule(rule_id, top);
2031            }
2032
2033            Property::Bottom(bottom) => {
2034                self.bottom.insert_rule(rule_id, bottom);
2035            }
2036
2037            // Size
2038            Property::Size(size) => {
2039                self.width.insert_rule(rule_id, size);
2040                self.height.insert_rule(rule_id, size);
2041            }
2042
2043            Property::Width(width) => {
2044                self.width.insert_rule(rule_id, width);
2045            }
2046
2047            Property::Height(height) => {
2048                self.height.insert_rule(rule_id, height);
2049            }
2050
2051            Property::AspectRatio(aspect_ratio) => {
2052                self.aspect_ratio.insert_rule(rule_id, aspect_ratio);
2053            }
2054
2055            // Padding
2056            Property::Padding(padding) => {
2057                self.padding_left.insert_rule(rule_id, padding);
2058                self.padding_right.insert_rule(rule_id, padding);
2059                self.padding_top.insert_rule(rule_id, padding);
2060                self.padding_bottom.insert_rule(rule_id, padding);
2061            }
2062
2063            Property::PaddingLeft(padding_left) => {
2064                self.padding_left.insert_rule(rule_id, padding_left);
2065            }
2066
2067            Property::PaddingRight(padding_right) => {
2068                self.padding_right.insert_rule(rule_id, padding_right);
2069            }
2070
2071            Property::PaddingTop(padding_top) => {
2072                self.padding_top.insert_rule(rule_id, padding_top);
2073            }
2074
2075            Property::PaddingBottom(padding_bottom) => {
2076                self.padding_bottom.insert_rule(rule_id, padding_bottom);
2077            }
2078
2079            Property::VerticalGap(vertical_gap) => {
2080                self.vertical_gap.insert_rule(rule_id, vertical_gap);
2081            }
2082
2083            Property::HorizontalGap(horizontal_gap) => {
2084                self.horizontal_gap.insert_rule(rule_id, horizontal_gap);
2085            }
2086
2087            Property::Gap(gap) => {
2088                self.horizontal_gap.insert_rule(rule_id, gap);
2089                self.vertical_gap.insert_rule(rule_id, gap);
2090            }
2091
2092            // Size Constraints
2093            Property::MinSize(min_size) => {
2094                self.min_width.insert_rule(rule_id, min_size);
2095                self.min_height.insert_rule(rule_id, min_size);
2096            }
2097
2098            Property::MinWidth(min_width) => {
2099                self.min_width.insert_rule(rule_id, min_width);
2100            }
2101
2102            Property::MinHeight(min_height) => {
2103                self.min_height.insert_rule(rule_id, min_height);
2104            }
2105
2106            Property::MaxSize(max_size) => {
2107                self.max_width.insert_rule(rule_id, max_size);
2108                self.max_height.insert_rule(rule_id, max_size);
2109            }
2110
2111            Property::MaxWidth(max_width) => {
2112                self.max_width.insert_rule(rule_id, max_width);
2113            }
2114
2115            Property::MaxHeight(max_height) => {
2116                self.max_height.insert_rule(rule_id, max_height);
2117            }
2118
2119            // Gap Constraints
2120            Property::MinGap(min_gap) => {
2121                self.min_horizontal_gap.insert_rule(rule_id, min_gap);
2122                self.min_vertical_gap.insert_rule(rule_id, min_gap);
2123            }
2124
2125            Property::MinHorizontalGap(min_gap) => {
2126                self.min_horizontal_gap.insert_rule(rule_id, min_gap);
2127            }
2128
2129            Property::MinVerticalGap(min_gap) => {
2130                self.min_vertical_gap.insert_rule(rule_id, min_gap);
2131            }
2132
2133            Property::MaxGap(max_gap) => {
2134                self.max_horizontal_gap.insert_rule(rule_id, max_gap);
2135                self.max_vertical_gap.insert_rule(rule_id, max_gap);
2136            }
2137
2138            Property::MaxHorizontalGap(max_gap) => {
2139                self.max_horizontal_gap.insert_rule(rule_id, max_gap);
2140            }
2141
2142            Property::MaxVerticalGap(max_gap) => {
2143                self.max_vertical_gap.insert_rule(rule_id, max_gap);
2144            }
2145
2146            // Background Colour
2147            Property::BackgroundColor(color) => {
2148                self.background_color.insert_rule(rule_id, color);
2149            }
2150
2151            // Border
2152            Property::Border(border) => {
2153                if let Some(color) = border.color {
2154                    self.border_top_color.insert_rule(rule_id, color);
2155                    self.border_right_color.insert_rule(rule_id, color);
2156                    self.border_bottom_color.insert_rule(rule_id, color);
2157                    self.border_left_color.insert_rule(rule_id, color);
2158                }
2159
2160                if let Some(width) = border.width {
2161                    let w: LengthOrPercentage = width.into();
2162                    self.border_top_width.insert_rule(rule_id, w.clone());
2163                    self.border_right_width.insert_rule(rule_id, w.clone());
2164                    self.border_bottom_width.insert_rule(rule_id, w.clone());
2165                    self.border_left_width.insert_rule(rule_id, w);
2166                }
2167
2168                if let Some(style) = border.style {
2169                    self.border_top_style.insert_rule(rule_id, style.top);
2170                    self.border_right_style.insert_rule(rule_id, style.right);
2171                    self.border_bottom_style.insert_rule(rule_id, style.bottom);
2172                    self.border_left_style.insert_rule(rule_id, style.left);
2173                }
2174            }
2175
2176            // Border side shorthands
2177            Property::BorderTop(border) => {
2178                if let Some(color) = border.color {
2179                    self.border_top_color.insert_rule(rule_id, color);
2180                }
2181                if let Some(width) = border.width {
2182                    self.border_top_width.insert_rule(rule_id, width.into());
2183                }
2184                if let Some(style) = border.style {
2185                    self.border_top_style.insert_rule(rule_id, style.top);
2186                }
2187            }
2188
2189            Property::BorderRight(border) => {
2190                if let Some(color) = border.color {
2191                    self.border_right_color.insert_rule(rule_id, color);
2192                }
2193                if let Some(width) = border.width {
2194                    self.border_right_width.insert_rule(rule_id, width.into());
2195                }
2196                if let Some(style) = border.style {
2197                    self.border_right_style.insert_rule(rule_id, style.right);
2198                }
2199            }
2200
2201            Property::BorderBottom(border) => {
2202                if let Some(color) = border.color {
2203                    self.border_bottom_color.insert_rule(rule_id, color);
2204                }
2205                if let Some(width) = border.width {
2206                    self.border_bottom_width.insert_rule(rule_id, width.into());
2207                }
2208                if let Some(style) = border.style {
2209                    self.border_bottom_style.insert_rule(rule_id, style.bottom);
2210                }
2211            }
2212
2213            Property::BorderLeft(border) => {
2214                if let Some(color) = border.color {
2215                    self.border_left_color.insert_rule(rule_id, color);
2216                }
2217                if let Some(width) = border.width {
2218                    self.border_left_width.insert_rule(rule_id, width.into());
2219                }
2220                if let Some(style) = border.style {
2221                    self.border_left_style.insert_rule(rule_id, style.left);
2222                }
2223            }
2224
2225            // Border Width
2226            Property::BorderWidth(border_width) => {
2227                self.border_top_width.insert_rule(rule_id, border_width.top.0);
2228                self.border_right_width.insert_rule(rule_id, border_width.right.0);
2229                self.border_bottom_width.insert_rule(rule_id, border_width.bottom.0);
2230                self.border_left_width.insert_rule(rule_id, border_width.left.0);
2231            }
2232
2233            Property::BorderTopWidth(width) => {
2234                self.border_top_width.insert_rule(rule_id, width.into());
2235            }
2236
2237            Property::BorderRightWidth(width) => {
2238                self.border_right_width.insert_rule(rule_id, width.into());
2239            }
2240
2241            Property::BorderBottomWidth(width) => {
2242                self.border_bottom_width.insert_rule(rule_id, width.into());
2243            }
2244
2245            Property::BorderLeftWidth(width) => {
2246                self.border_left_width.insert_rule(rule_id, width.into());
2247            }
2248
2249            // Border Color
2250            Property::BorderColor(color) => {
2251                self.border_top_color.insert_rule(rule_id, color);
2252                self.border_right_color.insert_rule(rule_id, color);
2253                self.border_bottom_color.insert_rule(rule_id, color);
2254                self.border_left_color.insert_rule(rule_id, color);
2255            }
2256
2257            Property::BorderTopColor(color) => {
2258                self.border_top_color.insert_rule(rule_id, color);
2259            }
2260
2261            Property::BorderRightColor(color) => {
2262                self.border_right_color.insert_rule(rule_id, color);
2263            }
2264
2265            Property::BorderBottomColor(color) => {
2266                self.border_bottom_color.insert_rule(rule_id, color);
2267            }
2268
2269            Property::BorderLeftColor(color) => {
2270                self.border_left_color.insert_rule(rule_id, color);
2271            }
2272
2273            // Border Style
2274            Property::BorderStyle(style) => {
2275                self.border_top_style.insert_rule(rule_id, style.top);
2276                self.border_right_style.insert_rule(rule_id, style.right);
2277                self.border_bottom_style.insert_rule(rule_id, style.bottom);
2278                self.border_left_style.insert_rule(rule_id, style.left);
2279            }
2280
2281            Property::BorderTopStyle(style) => {
2282                self.border_top_style.insert_rule(rule_id, style);
2283            }
2284
2285            Property::BorderRightStyle(style) => {
2286                self.border_right_style.insert_rule(rule_id, style);
2287            }
2288
2289            Property::BorderBottomStyle(style) => {
2290                self.border_bottom_style.insert_rule(rule_id, style);
2291            }
2292
2293            Property::BorderLeftStyle(style) => {
2294                self.border_left_style.insert_rule(rule_id, style);
2295            }
2296
2297            // Border Radius
2298            Property::CornerRadius(corner_radius) => {
2299                self.corner_bottom_left_radius.insert_rule(rule_id, corner_radius.bottom_left);
2300                self.corner_bottom_right_radius.insert_rule(rule_id, corner_radius.bottom_right);
2301                self.corner_top_left_radius.insert_rule(rule_id, corner_radius.top_left);
2302                self.corner_top_right_radius.insert_rule(rule_id, corner_radius.top_right);
2303            }
2304
2305            Property::CornerBottomLeftRadius(corner_radius) => {
2306                self.corner_bottom_left_radius.insert_rule(rule_id, corner_radius);
2307            }
2308
2309            Property::CornerTopLeftRadius(corner_radius) => {
2310                self.corner_top_left_radius.insert_rule(rule_id, corner_radius);
2311            }
2312
2313            Property::CornerBottomRightRadius(corner_radius) => {
2314                self.corner_bottom_right_radius.insert_rule(rule_id, corner_radius);
2315            }
2316
2317            Property::CornerTopRightRadius(corner_radius) => {
2318                self.corner_top_right_radius.insert_rule(rule_id, corner_radius);
2319            }
2320
2321            // Corner Shape
2322            Property::CornerShape(corner_shape) => {
2323                self.corner_top_left_shape.insert_rule(rule_id, corner_shape.0);
2324                self.corner_top_right_shape.insert_rule(rule_id, corner_shape.1);
2325                self.corner_bottom_right_shape.insert_rule(rule_id, corner_shape.2);
2326                self.corner_bottom_left_shape.insert_rule(rule_id, corner_shape.3);
2327            }
2328
2329            Property::CornerTopLeftShape(corner_shape) => {
2330                self.corner_top_left_shape.insert_rule(rule_id, corner_shape);
2331            }
2332
2333            Property::CornerTopRightShape(corner_shape) => {
2334                self.corner_top_right_shape.insert_rule(rule_id, corner_shape);
2335            }
2336
2337            Property::CornerBottomLeftShape(corner_shape) => {
2338                self.corner_bottom_left_shape.insert_rule(rule_id, corner_shape);
2339            }
2340
2341            Property::CornerBottomRightShape(corner_shape) => {
2342                self.corner_bottom_right_shape.insert_rule(rule_id, corner_shape);
2343            }
2344
2345            // Font Family
2346            Property::FontFamily(font_family) => {
2347                self.font_family.insert_rule(
2348                    rule_id,
2349                    font_family
2350                        .iter()
2351                        .map(|family| match family {
2352                            FontFamily::Named(name) => FamilyOwned::Named(name.to_string()),
2353                            FontFamily::Generic(generic) => FamilyOwned::Generic(*generic),
2354                        })
2355                        .collect::<Vec<_>>(),
2356                );
2357            }
2358
2359            // Font Color
2360            Property::FontColor(font_color) => {
2361                self.font_color.insert_rule(rule_id, font_color);
2362            }
2363
2364            // Font Size
2365            Property::FontSize(font_size) => {
2366                self.font_size.insert_rule(rule_id, font_size);
2367            }
2368
2369            // Letter Spacing
2370            Property::LetterSpacing(letter_spacing) => {
2371                self.letter_spacing.insert_rule(rule_id, letter_spacing);
2372            }
2373
2374            // Font Weight
2375            Property::FontWeight(font_weight) => {
2376                self.font_weight.insert_rule(rule_id, font_weight);
2377            }
2378
2379            // Font Slant
2380            Property::FontSlant(font_slant) => {
2381                self.font_slant.insert_rule(rule_id, font_slant);
2382            }
2383
2384            // Font Width
2385            Property::FontWidth(font_width) => {
2386                self.font_width.insert_rule(rule_id, font_width);
2387            }
2388
2389            // Font Variation Settings
2390            Property::FontVariationSettings(font_variation_settings) => {
2391                self.font_variation_settings.insert_rule(rule_id, font_variation_settings);
2392            }
2393
2394            // Caret Color
2395            Property::CaretColor(caret_color) => {
2396                self.caret_color.insert_rule(rule_id, caret_color);
2397            }
2398
2399            // Selection Color
2400            Property::SelectionColor(selection_color) => {
2401                self.selection_color.insert_rule(rule_id, selection_color);
2402            }
2403
2404            // Transform
2405            Property::Transform(transforms) => {
2406                self.transform.insert_rule(rule_id, transforms);
2407            }
2408
2409            Property::TransformOrigin(transform_origin) => {
2410                let x = transform_origin.x.to_length_or_percentage();
2411                let y = transform_origin.y.to_length_or_percentage();
2412                self.transform_origin.insert_rule(rule_id, Translate { x, y });
2413            }
2414
2415            Property::Translate(translate) => {
2416                self.translate.insert_rule(rule_id, translate);
2417            }
2418
2419            Property::Rotate(rotate) => {
2420                self.rotate.insert_rule(rule_id, rotate);
2421            }
2422
2423            Property::Scale(scale) => {
2424                self.scale.insert_rule(rule_id, scale);
2425            }
2426
2427            // Overflow
2428            Property::Overflow(overflow) => {
2429                self.overflowx.insert_rule(rule_id, overflow);
2430                self.overflowy.insert_rule(rule_id, overflow);
2431            }
2432
2433            Property::OverflowX(overflow) => {
2434                self.overflowx.insert_rule(rule_id, overflow);
2435            }
2436
2437            Property::OverflowY(overflow) => {
2438                self.overflowy.insert_rule(rule_id, overflow);
2439            }
2440
2441            // Z Index
2442            Property::ZIndex(z_index) => self.z_index.insert_rule(rule_id, z_index),
2443
2444            // Outline
2445            Property::Outline(outline) => {
2446                if let Some(outline_color) = outline.color {
2447                    self.outline_color.insert_rule(rule_id, outline_color);
2448                }
2449
2450                if let Some(outline_width) = outline.width {
2451                    self.outline_width.insert_rule(rule_id, outline_width.into());
2452                }
2453            }
2454
2455            Property::OutlineColor(outline_color) => {
2456                self.outline_color.insert_rule(rule_id, outline_color);
2457            }
2458
2459            Property::OutlineWidth(outline_width) => {
2460                self.outline_width.insert_rule(rule_id, outline_width.left.0);
2461            }
2462
2463            Property::OutlineOffset(outline_offset) => {
2464                self.outline_offset.insert_rule(rule_id, outline_offset);
2465            }
2466
2467            // Background Images & Gradients
2468            Property::BackgroundImage(images) => {
2469                let images = images
2470                    .into_iter()
2471                    .filter_map(|img| match img {
2472                        BackgroundImage::None => None,
2473                        BackgroundImage::Gradient(gradient) => {
2474                            Some(ImageOrGradient::Gradient(*gradient))
2475                        }
2476                        BackgroundImage::Url(url) => {
2477                            Some(ImageOrGradient::Image(url.url.to_string()))
2478                        }
2479                    })
2480                    .collect::<Vec<_>>();
2481
2482                self.background_image.insert_rule(rule_id, images);
2483            }
2484
2485            // Background Position
2486            Property::BackgroundPosition(positions) => {
2487                self.background_position.insert_rule(rule_id, positions);
2488            }
2489
2490            // Background Size
2491            Property::BackgroundSize(sizes) => {
2492                self.background_size.insert_rule(rule_id, sizes);
2493            }
2494
2495            // Background Repeat
2496            Property::BackgroundRepeat(repeats) => {
2497                self.background_repeat.insert_rule(rule_id, repeats);
2498            }
2499
2500            // Text Wrapping
2501            Property::TextWrap(text_wrap) => {
2502                self.text_wrap.insert_rule(rule_id, text_wrap);
2503            }
2504
2505            // Text Alignment
2506            Property::TextAlign(text_align) => {
2507                self.text_align.insert_rule(rule_id, text_align);
2508            }
2509
2510            // Box Shadows
2511            Property::Shadow(shadows) => {
2512                self.shadow.insert_rule(rule_id, shadows);
2513            }
2514
2515            // Cursor Icon
2516            Property::Cursor(cursor) => {
2517                self.cursor.insert_rule(rule_id, cursor);
2518            }
2519
2520            Property::PointerEvents(pointer_events) => {
2521                self.pointer_events.insert_rule(rule_id, pointer_events);
2522            }
2523
2524            Property::TextOverflow(text_overflow) => {
2525                self.text_overflow.insert_rule(rule_id, text_overflow);
2526            }
2527            Property::LineHeight(line_height) => {
2528                self.line_height.insert_rule(rule_id, line_height);
2529            }
2530            Property::LineClamp(line_clamp) => {
2531                self.line_clamp.insert_rule(rule_id, line_clamp);
2532            }
2533            Property::TextDecoration(decoration) => {
2534                self.text_decoration_line.insert_rule(rule_id, decoration.line);
2535                self.text_decoration_style.insert_rule(rule_id, decoration.style);
2536                self.text_decoration_color.insert_rule(rule_id, decoration.color.into());
2537            }
2538            Property::TextDecorationLine(line) => {
2539                self.text_decoration_line.insert_rule(rule_id, line);
2540            }
2541            Property::TextDecorationColor(decoration_color) => {
2542                self.text_decoration_color.insert_rule(rule_id, decoration_color);
2543            }
2544            Property::TextDecorationStyle(decoration_style) => {
2545                self.text_decoration_style.insert_rule(rule_id, decoration_style);
2546            }
2547            Property::TextStroke(stroke) => {
2548                self.text_stroke_width.insert_rule(rule_id, stroke.width);
2549                self.text_stroke_style.insert_rule(rule_id, stroke.style);
2550            }
2551            Property::TextStrokeWidth(stroke_width) => {
2552                self.text_stroke_width.insert_rule(rule_id, stroke_width);
2553            }
2554            Property::TextStrokeStyle(stroke_style) => {
2555                self.text_stroke_style.insert_rule(rule_id, stroke_style);
2556            }
2557            Property::Fill(fill) => {
2558                self.fill.insert_rule(rule_id, fill);
2559            }
2560
2561            // Unparsed. TODO: Log the error.
2562            Property::Unparsed(unparsed) => {
2563                macro_rules! parse_color_var {
2564                    ($($prop:expr),+) => {
2565                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2566                            let hash = variable_hash(var);
2567                            let fallback = color_fallback(var);
2568                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
2569                        }
2570                    };
2571                }
2572                macro_rules! parse_length_var {
2573                    ($($prop:expr),+) => {
2574                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2575                            let hash = variable_hash(var);
2576                            let fallback = length_fallback(var);
2577                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
2578                        }
2579                    };
2580                }
2581                macro_rules! parse_font_size_var {
2582                    ($prop:expr) => {
2583                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2584                            $prop.insert_variable_rule(
2585                                rule_id,
2586                                variable_hash(var),
2587                                font_size_fallback(var),
2588                            );
2589                        }
2590                    };
2591                }
2592                macro_rules! parse_letter_spacing_var {
2593                    ($prop:expr) => {
2594                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2595                            $prop.insert_variable_rule(
2596                                rule_id,
2597                                variable_hash(var),
2598                                letter_spacing_fallback(var),
2599                            );
2600                        }
2601                    };
2602                }
2603                macro_rules! parse_line_height_var {
2604                    ($prop:expr) => {
2605                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2606                            $prop.insert_variable_rule(
2607                                rule_id,
2608                                variable_hash(var),
2609                                line_height_fallback(var),
2610                            );
2611                        }
2612                    };
2613                }
2614                macro_rules! parse_units_var {
2615                    ($($prop:expr),+) => {
2616                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2617                            let hash = variable_hash(var);
2618                            let fallback = units_fallback(var);
2619                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
2620                        }
2621                    };
2622                }
2623                match unparsed.name.as_ref() {
2624                    "background-color" => parse_color_var!(self.background_color),
2625                    "border-color" => parse_color_var!(
2626                        self.border_top_color,
2627                        self.border_right_color,
2628                        self.border_bottom_color,
2629                        self.border_left_color
2630                    ),
2631                    "outline-color" => parse_color_var!(self.outline_color),
2632                    "color" => parse_color_var!(self.font_color),
2633                    "caret-color" => parse_color_var!(self.caret_color),
2634                    "selection-color" => parse_color_var!(self.selection_color),
2635                    "fill" => parse_color_var!(self.fill),
2636                    "text-decoration-color" => parse_color_var!(self.text_decoration_color),
2637                    "font-size" => parse_font_size_var!(self.font_size),
2638                    "letter-spacing" => parse_letter_spacing_var!(self.letter_spacing),
2639                    "line-height" => parse_line_height_var!(self.line_height),
2640                    "corner-radius" => parse_length_var!(
2641                        self.corner_top_left_radius,
2642                        self.corner_top_right_radius,
2643                        self.corner_bottom_left_radius,
2644                        self.corner_bottom_right_radius
2645                    ),
2646                    "corner-top-left-radius" => parse_length_var!(self.corner_top_left_radius),
2647                    "corner-top-right-radius" => parse_length_var!(self.corner_top_right_radius),
2648                    "corner-bottom-left-radius" => {
2649                        parse_length_var!(self.corner_bottom_left_radius)
2650                    }
2651                    "corner-bottom-right-radius" => {
2652                        parse_length_var!(self.corner_bottom_right_radius)
2653                    }
2654                    "border-width" => parse_length_var!(
2655                        self.border_top_width,
2656                        self.border_right_width,
2657                        self.border_bottom_width,
2658                        self.border_left_width
2659                    ),
2660                    "border-top-width" => parse_length_var!(self.border_top_width),
2661                    "border-right-width" => parse_length_var!(self.border_right_width),
2662                    "border-bottom-width" => parse_length_var!(self.border_bottom_width),
2663                    "border-left-width" => parse_length_var!(self.border_left_width),
2664                    "border-top-color" => parse_color_var!(self.border_top_color),
2665                    "border-right-color" => parse_color_var!(self.border_right_color),
2666                    "border-bottom-color" => parse_color_var!(self.border_bottom_color),
2667                    "border-left-color" => parse_color_var!(self.border_left_color),
2668                    "border" => {
2669                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2670                            let hash = variable_hash(var);
2671                            let lf = length_fallback(var);
2672                            let cf = color_fallback(var);
2673                            self.border_top_width.insert_variable_rule(rule_id, hash, lf.clone());
2674                            self.border_right_width.insert_variable_rule(rule_id, hash, lf.clone());
2675                            self.border_bottom_width.insert_variable_rule(
2676                                rule_id,
2677                                hash,
2678                                lf.clone(),
2679                            );
2680                            self.border_left_width.insert_variable_rule(rule_id, hash, lf);
2681                            self.border_top_color.insert_variable_rule(rule_id, hash, cf);
2682                            self.border_right_color.insert_variable_rule(rule_id, hash, cf);
2683                            self.border_bottom_color.insert_variable_rule(rule_id, hash, cf);
2684                            self.border_left_color.insert_variable_rule(rule_id, hash, cf);
2685                        }
2686                    }
2687                    "outline" => {
2688                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2689                            let hash = variable_hash(var);
2690                            self.outline_width.insert_variable_rule(
2691                                rule_id,
2692                                hash,
2693                                length_fallback(var),
2694                            );
2695                            self.outline_color.insert_variable_rule(
2696                                rule_id,
2697                                hash,
2698                                color_fallback(var),
2699                            );
2700                        }
2701                    }
2702                    "outline-width" => parse_length_var!(self.outline_width),
2703                    "outline-offset" => parse_length_var!(self.outline_offset),
2704                    "left" => parse_units_var!(self.left),
2705                    "right" => parse_units_var!(self.right),
2706                    "top" => parse_units_var!(self.top),
2707                    "bottom" => parse_units_var!(self.bottom),
2708                    "space" => parse_units_var!(self.left, self.right, self.top, self.bottom),
2709                    "width" => parse_units_var!(self.width),
2710                    "height" => parse_units_var!(self.height),
2711                    "size" => parse_units_var!(self.width, self.height),
2712                    "min-width" => parse_units_var!(self.min_width),
2713                    "max-width" => parse_units_var!(self.max_width),
2714                    "min-height" => parse_units_var!(self.min_height),
2715                    "max-height" => parse_units_var!(self.max_height),
2716                    "min-size" => parse_units_var!(self.min_width, self.min_height),
2717                    "max-size" => parse_units_var!(self.max_width, self.max_height),
2718                    "padding-left" => parse_units_var!(self.padding_left),
2719                    "padding-right" => parse_units_var!(self.padding_right),
2720                    "padding-top" => parse_units_var!(self.padding_top),
2721                    "padding-bottom" => parse_units_var!(self.padding_bottom),
2722                    "padding" => parse_units_var!(
2723                        self.padding_left,
2724                        self.padding_right,
2725                        self.padding_top,
2726                        self.padding_bottom
2727                    ),
2728                    "row-gap" | "vertical-gap" => parse_units_var!(self.vertical_gap),
2729                    "column-gap" | "horizontal-gap" => parse_units_var!(self.horizontal_gap),
2730                    "gap" => parse_units_var!(self.vertical_gap, self.horizontal_gap),
2731                    "min-gap" => {
2732                        parse_units_var!(self.min_horizontal_gap, self.min_vertical_gap)
2733                    }
2734                    "max-gap" => {
2735                        parse_units_var!(self.max_horizontal_gap, self.max_vertical_gap)
2736                    }
2737                    "opacity" => {
2738                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2739                            self.opacity.insert_variable_rule(
2740                                rule_id,
2741                                variable_hash(var),
2742                                opacity_fallback(var),
2743                            );
2744                        }
2745                    }
2746                    "shadow" => {
2747                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2748                            self.shadow.insert_variable_rule(
2749                                rule_id,
2750                                variable_hash(var),
2751                                shadow_fallback(var),
2752                            );
2753                        }
2754                    }
2755                    n => warn!("Unparsed {} {:?}", n, unparsed.value),
2756                }
2757            }
2758
2759            Property::Custom(custom) => {
2760                let mut s = DefaultHasher::new();
2761                custom.name.hash(&mut s);
2762                let variable_name_hash = s.finish();
2763
2764                if let Some(shadows) = parse_shadow_list(&custom.value.0) {
2765                    if let Some(store) = self.custom_shadow_props.get_mut(&variable_name_hash) {
2766                        store.insert_rule(rule_id, shadows);
2767                    } else {
2768                        let mut store = AnimatableVarSet::default();
2769                        store.insert_rule(rule_id, shadows);
2770                        self.custom_shadow_props.insert(variable_name_hash, store);
2771                    }
2772                }
2773
2774                // Parse custom properties and store them
2775                for token in custom.value.0.iter() {
2776                    // Try parsing colors
2777                    if let TokenOrValue::Color(color) = token {
2778                        if let Some(store) = self.custom_color_props.get_mut(&variable_name_hash) {
2779                            store.insert_rule(rule_id, *color);
2780                        } else {
2781                            let mut store = AnimatableVarSet::default();
2782                            store.insert_rule(rule_id, *color);
2783                            self.custom_color_props.insert(variable_name_hash, store);
2784                        }
2785                    }
2786
2787                    // Parse length/percentage tokens into custom_length_props
2788                    match token {
2789                        TokenOrValue::Token(CssToken::Dimension { value, unit, .. }) => {
2790                            let lop = if unit.as_ref().eq_ignore_ascii_case("px") {
2791                                Some(LengthOrPercentage::Length(Length::Value(LengthValue::Px(
2792                                    *value,
2793                                ))))
2794                            } else {
2795                                None
2796                            };
2797                            if let Some(lop) = lop {
2798                                if let Some(store) =
2799                                    self.custom_length_props.get_mut(&variable_name_hash)
2800                                {
2801                                    store.insert_rule(rule_id, lop.clone());
2802                                } else {
2803                                    let mut store = AnimatableVarSet::default();
2804                                    store.insert_rule(rule_id, lop.clone());
2805                                    self.custom_length_props.insert(variable_name_hash, store);
2806                                }
2807                                // Also try storing as FontSize
2808                                let fs = FontSize(Length::Value(LengthValue::Px(*value)));
2809                                if let Some(store) =
2810                                    self.custom_font_size_props.get_mut(&variable_name_hash)
2811                                {
2812                                    store.insert_rule(rule_id, fs);
2813                                } else {
2814                                    let mut store = AnimatableVarSet::default();
2815                                    store.insert_rule(rule_id, fs);
2816                                    self.custom_font_size_props.insert(variable_name_hash, store);
2817                                }
2818                                // Also try storing as LetterSpacing::Length
2819                                let letter_spacing =
2820                                    LetterSpacing::Length(Length::Value(LengthValue::Px(*value)));
2821                                if let Some(store) =
2822                                    self.custom_letter_spacing_props.get_mut(&variable_name_hash)
2823                                {
2824                                    store.insert_rule(rule_id, letter_spacing);
2825                                } else {
2826                                    let mut store = AnimatableVarSet::default();
2827                                    store.insert_rule(rule_id, letter_spacing);
2828                                    self.custom_letter_spacing_props
2829                                        .insert(variable_name_hash, store);
2830                                }
2831                                // Also try storing as LineHeight::Length
2832                                let line_height =
2833                                    LineHeight::Length(Length::Value(LengthValue::Px(*value)));
2834                                if let Some(store) =
2835                                    self.custom_line_height_props.get_mut(&variable_name_hash)
2836                                {
2837                                    store.insert_rule(rule_id, line_height);
2838                                } else {
2839                                    let mut store = AnimatableVarSet::default();
2840                                    store.insert_rule(rule_id, line_height);
2841                                    self.custom_line_height_props.insert(variable_name_hash, store);
2842                                }
2843                                // Also store as Units::Pixels
2844                                let units_val = Units::Pixels(*value);
2845                                if let Some(store) =
2846                                    self.custom_units_props.get_mut(&variable_name_hash)
2847                                {
2848                                    store.insert_rule(rule_id, units_val);
2849                                } else {
2850                                    let mut store = AnimatableVarSet::default();
2851                                    store.insert_rule(rule_id, units_val);
2852                                    self.custom_units_props.insert(variable_name_hash, store);
2853                                }
2854                            } else if unit.as_ref().eq_ignore_ascii_case("s") {
2855                                // "1s" => Units::Stretch(1.0)
2856                                let units_val = Units::Stretch(*value);
2857                                if let Some(store) =
2858                                    self.custom_units_props.get_mut(&variable_name_hash)
2859                                {
2860                                    store.insert_rule(rule_id, units_val);
2861                                } else {
2862                                    let mut store = AnimatableVarSet::default();
2863                                    store.insert_rule(rule_id, units_val);
2864                                    self.custom_units_props.insert(variable_name_hash, store);
2865                                }
2866                            }
2867                        }
2868                        TokenOrValue::Token(CssToken::Ident(ident))
2869                            if ident.as_ref().eq_ignore_ascii_case("auto") =>
2870                        {
2871                            let units_val = Units::Auto;
2872                            if let Some(store) =
2873                                self.custom_units_props.get_mut(&variable_name_hash)
2874                            {
2875                                store.insert_rule(rule_id, units_val);
2876                            } else {
2877                                let mut store = AnimatableVarSet::default();
2878                                store.insert_rule(rule_id, units_val);
2879                                self.custom_units_props.insert(variable_name_hash, store);
2880                            }
2881                        }
2882                        TokenOrValue::Token(CssToken::Percentage { unit_value, .. }) => {
2883                            let lop = LengthOrPercentage::Percentage(*unit_value * 100.0);
2884                            if let Some(store) =
2885                                self.custom_length_props.get_mut(&variable_name_hash)
2886                            {
2887                                store.insert_rule(rule_id, lop);
2888                            } else {
2889                                let mut store = AnimatableVarSet::default();
2890                                store.insert_rule(rule_id, lop);
2891                                self.custom_length_props.insert(variable_name_hash, store);
2892                            }
2893                            // Also store as LineHeight::Percentage
2894                            let line_height = LineHeight::Percentage(*unit_value * 100.0);
2895                            if let Some(store) =
2896                                self.custom_line_height_props.get_mut(&variable_name_hash)
2897                            {
2898                                store.insert_rule(rule_id, line_height);
2899                            } else {
2900                                let mut store = AnimatableVarSet::default();
2901                                store.insert_rule(rule_id, line_height);
2902                                self.custom_line_height_props.insert(variable_name_hash, store);
2903                            }
2904                            // Also store as Units::Percentage
2905                            let units_val = Units::Percentage(*unit_value * 100.0);
2906                            if let Some(store) =
2907                                self.custom_units_props.get_mut(&variable_name_hash)
2908                            {
2909                                store.insert_rule(rule_id, units_val);
2910                            } else {
2911                                let mut store = AnimatableVarSet::default();
2912                                store.insert_rule(rule_id, units_val);
2913                                self.custom_units_props.insert(variable_name_hash, store);
2914                            }
2915                            // Also store as Opacity (percentage as 0..1)
2916                            let opacity_val = Opacity(*unit_value);
2917                            if let Some(store) =
2918                                self.custom_opacity_props.get_mut(&variable_name_hash)
2919                            {
2920                                store.insert_rule(rule_id, opacity_val);
2921                            } else {
2922                                let mut store = AnimatableVarSet::default();
2923                                store.insert_rule(rule_id, opacity_val);
2924                                self.custom_opacity_props.insert(variable_name_hash, store);
2925                            }
2926                        }
2927                        TokenOrValue::Var(var) => {
2928                            let name_hash = variable_hash(var);
2929                            // Store var reference in all maps (type is unknown at parse time)
2930                            if let Some(store) =
2931                                self.custom_color_props.get_mut(&variable_name_hash)
2932                            {
2933                                store.insert_variable_rule(rule_id, name_hash, color_fallback(var));
2934                            } else {
2935                                let mut store = AnimatableVarSet::default();
2936                                store.insert_variable_rule(rule_id, name_hash, color_fallback(var));
2937                                self.custom_color_props.insert(variable_name_hash, store);
2938                            }
2939                            if let Some(store) =
2940                                self.custom_length_props.get_mut(&variable_name_hash)
2941                            {
2942                                store.insert_variable_rule(
2943                                    rule_id,
2944                                    name_hash,
2945                                    length_fallback(var),
2946                                );
2947                            } else {
2948                                let mut store: AnimatableVarSet<LengthOrPercentage> =
2949                                    AnimatableVarSet::default();
2950                                store.insert_variable_rule(
2951                                    rule_id,
2952                                    name_hash,
2953                                    length_fallback(var),
2954                                );
2955                                self.custom_length_props.insert(variable_name_hash, store);
2956                            }
2957                            if let Some(store) =
2958                                self.custom_font_size_props.get_mut(&variable_name_hash)
2959                            {
2960                                store.insert_variable_rule(
2961                                    rule_id,
2962                                    name_hash,
2963                                    font_size_fallback(var),
2964                                );
2965                            } else {
2966                                let mut store: AnimatableVarSet<FontSize> =
2967                                    AnimatableVarSet::default();
2968                                store.insert_variable_rule(
2969                                    rule_id,
2970                                    name_hash,
2971                                    font_size_fallback(var),
2972                                );
2973                                self.custom_font_size_props.insert(variable_name_hash, store);
2974                            }
2975                            if let Some(store) =
2976                                self.custom_letter_spacing_props.get_mut(&variable_name_hash)
2977                            {
2978                                store.insert_variable_rule(
2979                                    rule_id,
2980                                    name_hash,
2981                                    letter_spacing_fallback(var),
2982                                );
2983                            } else {
2984                                let mut store: AnimatableVarSet<LetterSpacing> =
2985                                    AnimatableVarSet::default();
2986                                store.insert_variable_rule(
2987                                    rule_id,
2988                                    name_hash,
2989                                    letter_spacing_fallback(var),
2990                                );
2991                                self.custom_letter_spacing_props.insert(variable_name_hash, store);
2992                            }
2993                            if let Some(store) =
2994                                self.custom_line_height_props.get_mut(&variable_name_hash)
2995                            {
2996                                store.insert_variable_rule(
2997                                    rule_id,
2998                                    name_hash,
2999                                    line_height_fallback(var),
3000                                );
3001                            } else {
3002                                let mut store: AnimatableVarSet<LineHeight> =
3003                                    AnimatableVarSet::default();
3004                                store.insert_variable_rule(
3005                                    rule_id,
3006                                    name_hash,
3007                                    line_height_fallback(var),
3008                                );
3009                                self.custom_line_height_props.insert(variable_name_hash, store);
3010                            }
3011                            if let Some(store) =
3012                                self.custom_units_props.get_mut(&variable_name_hash)
3013                            {
3014                                store.insert_variable_rule(rule_id, name_hash, units_fallback(var));
3015                            } else {
3016                                let mut store: AnimatableVarSet<Units> =
3017                                    AnimatableVarSet::default();
3018                                store.insert_variable_rule(rule_id, name_hash, units_fallback(var));
3019                                self.custom_units_props.insert(variable_name_hash, store);
3020                            }
3021                            if let Some(store) =
3022                                self.custom_opacity_props.get_mut(&variable_name_hash)
3023                            {
3024                                store.insert_variable_rule(
3025                                    rule_id,
3026                                    name_hash,
3027                                    opacity_fallback(var),
3028                                );
3029                            } else {
3030                                let mut store: AnimatableVarSet<Opacity> =
3031                                    AnimatableVarSet::default();
3032                                store.insert_variable_rule(
3033                                    rule_id,
3034                                    name_hash,
3035                                    opacity_fallback(var),
3036                                );
3037                                self.custom_opacity_props.insert(variable_name_hash, store);
3038                            }
3039
3040                            if let Some(store) =
3041                                self.custom_shadow_props.get_mut(&variable_name_hash)
3042                            {
3043                                store.insert_variable_rule(
3044                                    rule_id,
3045                                    name_hash,
3046                                    shadow_fallback(var),
3047                                );
3048                            } else {
3049                                let mut store: AnimatableVarSet<Vec<Shadow>> =
3050                                    AnimatableVarSet::default();
3051                                store.insert_variable_rule(
3052                                    rule_id,
3053                                    name_hash,
3054                                    shadow_fallback(var),
3055                                );
3056                                self.custom_shadow_props.insert(variable_name_hash, store);
3057                            }
3058                        }
3059                        TokenOrValue::Token(CssToken::Number { value, .. }) => {
3060                            // Plain number like 0.5 → Opacity
3061                            let opacity_val = Opacity(*value);
3062                            if let Some(store) =
3063                                self.custom_opacity_props.get_mut(&variable_name_hash)
3064                            {
3065                                store.insert_rule(rule_id, opacity_val);
3066                            } else {
3067                                let mut store = AnimatableVarSet::default();
3068                                store.insert_rule(rule_id, opacity_val);
3069                                self.custom_opacity_props.insert(variable_name_hash, store);
3070                            }
3071
3072                            // Plain number like 1.2 -> LineHeight::Number
3073                            let line_height = LineHeight::Number(*value);
3074                            if let Some(store) =
3075                                self.custom_line_height_props.get_mut(&variable_name_hash)
3076                            {
3077                                store.insert_rule(rule_id, line_height);
3078                            } else {
3079                                let mut store = AnimatableVarSet::default();
3080                                store.insert_rule(rule_id, line_height);
3081                                self.custom_line_height_props.insert(variable_name_hash, store);
3082                            }
3083                        }
3084                        TokenOrValue::Token(CssToken::Ident(ident))
3085                            if ident.as_ref().eq_ignore_ascii_case("normal") =>
3086                        {
3087                            let line_height = LineHeight::Normal;
3088                            if let Some(store) =
3089                                self.custom_line_height_props.get_mut(&variable_name_hash)
3090                            {
3091                                store.insert_rule(rule_id, line_height);
3092                            } else {
3093                                let mut store = AnimatableVarSet::default();
3094                                store.insert_rule(rule_id, line_height);
3095                                self.custom_line_height_props.insert(variable_name_hash, store);
3096                            }
3097
3098                            let letter_spacing = LetterSpacing::Normal;
3099                            if let Some(store) =
3100                                self.custom_letter_spacing_props.get_mut(&variable_name_hash)
3101                            {
3102                                store.insert_rule(rule_id, letter_spacing);
3103                            } else {
3104                                let mut store = AnimatableVarSet::default();
3105                                store.insert_rule(rule_id, letter_spacing);
3106                                self.custom_letter_spacing_props.insert(variable_name_hash, store);
3107                            }
3108                        }
3109                        _ => {}
3110                    }
3111                }
3112            }
3113            _ => {}
3114        }
3115    }
3116
3117    // Helper function for generating AnimationState from a transition definition.
3118    fn add_transition<T: Default + Interpolator>(
3119        &self,
3120        transition: &Transition,
3121    ) -> AnimationState<T> {
3122        let timing_function = transition
3123            .timing_function
3124            .map(|easing| match easing {
3125                EasingFunction::Linear => TimingFunction::linear(),
3126                EasingFunction::Ease => TimingFunction::ease(),
3127                EasingFunction::EaseIn => TimingFunction::ease_in(),
3128                EasingFunction::EaseOut => TimingFunction::ease_out(),
3129                EasingFunction::EaseInOut => TimingFunction::ease_in_out(),
3130                EasingFunction::CubicBezier(x1, y1, x2, y2) => TimingFunction::new(x1, y1, x2, y2),
3131            })
3132            .unwrap_or_default();
3133
3134        AnimationState::new(Animation::null())
3135            .with_duration(transition.duration)
3136            .with_delay(transition.delay.unwrap_or_default())
3137            .with_keyframe(Keyframe { time: 0.0, value: Default::default(), timing_function })
3138            .with_keyframe(Keyframe { time: 1.0, value: Default::default(), timing_function })
3139    }
3140
3141    // Add style data for the given entity.
3142    pub(crate) fn add(&mut self, entity: Entity) {
3143        self.pseudo_classes.insert(entity, PseudoClassFlags::VALID);
3144        self.classes.insert(entity, HashSet::new());
3145        self.abilities.insert(entity, Abilities::default());
3146        self.system_flags = SystemFlags::RELAYOUT;
3147        // Adding an entity is a structural change. Relayout incrementally from the new entity;
3148        // morphorm restarts from at least its parent, which repositions all of the parent's
3149        // children. Marking the root here would force a full tree relayout on every view creation.
3150        self.relayout.insert(entity);
3151        self.restyle.insert(entity);
3152        self.reaccess.insert(entity);
3153        self.retransform.insert(entity);
3154        self.reclip.insert(entity);
3155    }
3156
3157    // Remove style data for the given entity.
3158    pub(crate) fn remove(&mut self, entity: Entity) {
3159        self.relayout.remove(&entity);
3160        self.laid_out.remove(&entity);
3161        self.ids.remove(entity);
3162        self.classes.remove(entity);
3163        self.pseudo_classes.remove(entity);
3164        self.disabled.remove(entity);
3165        self.abilities.remove(entity);
3166
3167        self.name.remove(entity);
3168        self.role.remove(entity);
3169        // self.default_action_verb.remove(entity);
3170        self.live.remove(entity);
3171        self.labelled_by.remove(entity);
3172        self.described_by.remove(entity);
3173        self.controls.remove(entity);
3174        self.active_descendant.remove(entity);
3175        self.expanded.remove(entity);
3176        self.selected.remove(entity);
3177        self.multiselectable.remove(entity);
3178        self.hidden.remove(entity);
3179        self.orientation.remove(entity);
3180        self.text_value.remove(entity);
3181        self.numeric_value.remove(entity);
3182
3183        // Display
3184        self.display.remove(entity);
3185        // Visibility
3186        self.visibility.remove(entity);
3187        // Opacity
3188        self.opacity.remove(entity);
3189        // Z Order
3190        self.z_index.remove(entity);
3191        self.ignore_clipping.remove(entity);
3192        // Clipping
3193        self.clip_path.remove(entity);
3194
3195        self.overflowx.remove(entity);
3196        self.overflowy.remove(entity);
3197
3198        // Filters
3199        self.filter.remove(entity);
3200        self.backdrop_filter.remove(entity);
3201
3202        // Blend Mode
3203        self.blend_mode.remove(entity);
3204
3205        // Transform
3206        self.transform.remove(entity);
3207        self.transform_origin.remove(entity);
3208        self.translate.remove(entity);
3209        self.rotate.remove(entity);
3210        self.scale.remove(entity);
3211
3212        // Border widths
3213        self.border_top_width.remove(entity);
3214        self.border_right_width.remove(entity);
3215        self.border_bottom_width.remove(entity);
3216        self.border_left_width.remove(entity);
3217        // Border colors
3218        self.border_top_color.remove(entity);
3219        self.border_right_color.remove(entity);
3220        self.border_bottom_color.remove(entity);
3221        self.border_left_color.remove(entity);
3222        // Border styles
3223        self.border_top_style.remove(entity);
3224        self.border_right_style.remove(entity);
3225        self.border_bottom_style.remove(entity);
3226        self.border_left_style.remove(entity);
3227
3228        // Corner Shape
3229        self.corner_bottom_left_shape.remove(entity);
3230        self.corner_bottom_right_shape.remove(entity);
3231        self.corner_top_left_shape.remove(entity);
3232        self.corner_top_right_shape.remove(entity);
3233
3234        // Corner Radius
3235        self.corner_bottom_left_radius.remove(entity);
3236        self.corner_bottom_right_radius.remove(entity);
3237        self.corner_top_left_radius.remove(entity);
3238        self.corner_top_right_radius.remove(entity);
3239
3240        // Corner Smoothing
3241        self.corner_bottom_left_smoothing.remove(entity);
3242        self.corner_bottom_right_smoothing.remove(entity);
3243        self.corner_top_left_smoothing.remove(entity);
3244        self.corner_top_right_smoothing.remove(entity);
3245
3246        // Outline
3247        self.outline_width.remove(entity);
3248        self.outline_color.remove(entity);
3249        self.outline_offset.remove(entity);
3250
3251        // Background
3252        self.background_color.remove(entity);
3253        self.background_image.remove(entity);
3254        self.background_position.remove(entity);
3255        self.background_repeat.remove(entity);
3256        self.background_size.remove(entity);
3257
3258        // Box Shadow
3259        self.shadow.remove(entity);
3260
3261        // Text and Font
3262        self.text.remove(entity);
3263        self.text_wrap.remove(entity);
3264        self.text_overflow.remove(entity);
3265        self.letter_spacing.remove(entity);
3266        self.line_height.remove(entity);
3267        self.line_clamp.remove(entity);
3268        self.text_align.remove(entity);
3269        self.font_family.remove(entity);
3270        self.font_color.remove(entity);
3271        self.font_size.remove(entity);
3272        self.font_weight.remove(entity);
3273        self.font_slant.remove(entity);
3274        self.font_width.remove(entity);
3275        self.font_variation_settings.remove(entity);
3276        self.caret_color.remove(entity);
3277        self.selection_color.remove(entity);
3278        self.text_decoration_line.remove(entity);
3279        self.text_decoration_style.remove(entity);
3280        self.text_decoration_color.remove(entity);
3281        self.text_stroke_width.remove(entity);
3282        self.text_stroke_style.remove(entity);
3283
3284        // Cursor
3285        self.cursor.remove(entity);
3286
3287        self.pointer_events.remove(entity);
3288
3289        // Layout Type
3290        self.layout_type.remove(entity);
3291
3292        // Position Type
3293        self.position_type.remove(entity);
3294
3295        self.alignment.remove(entity);
3296        self.direction.remove(entity);
3297        self.wrap.remove(entity);
3298
3299        // Grid
3300        self.grid_columns.remove(entity);
3301        self.grid_rows.remove(entity);
3302        self.column_start.remove(entity);
3303        self.column_span.remove(entity);
3304        self.row_start.remove(entity);
3305        self.row_span.remove(entity);
3306
3307        // Space
3308        self.left.remove(entity);
3309        self.right.remove(entity);
3310        self.top.remove(entity);
3311        self.bottom.remove(entity);
3312
3313        // Padding
3314        self.padding_left.remove(entity);
3315        self.padding_right.remove(entity);
3316        self.padding_top.remove(entity);
3317        self.padding_bottom.remove(entity);
3318        self.vertical_gap.remove(entity);
3319        self.horizontal_gap.remove(entity);
3320
3321        // Size
3322        self.width.remove(entity);
3323        self.height.remove(entity);
3324        self.aspect_ratio.remove(entity);
3325
3326        // Size Constraints
3327        self.min_width.remove(entity);
3328        self.max_width.remove(entity);
3329        self.min_height.remove(entity);
3330        self.max_height.remove(entity);
3331
3332        self.min_horizontal_gap.remove(entity);
3333        self.max_horizontal_gap.remove(entity);
3334        self.min_vertical_gap.remove(entity);
3335        self.max_vertical_gap.remove(entity);
3336
3337        self.text_range.remove(entity);
3338        self.text_span.remove(entity);
3339
3340        self.fill.remove(entity);
3341
3342        // Remove per-entity data from custom property stores
3343        for store in self.custom_color_props.values_mut() {
3344            store.remove(entity);
3345        }
3346        for store in self.custom_length_props.values_mut() {
3347            store.remove(entity);
3348        }
3349        for store in self.custom_font_size_props.values_mut() {
3350            store.remove(entity);
3351        }
3352        for store in self.custom_letter_spacing_props.values_mut() {
3353            store.remove(entity);
3354        }
3355        for store in self.custom_line_height_props.values_mut() {
3356            store.remove(entity);
3357        }
3358        for store in self.custom_units_props.values_mut() {
3359            store.remove(entity);
3360        }
3361        for store in self.custom_opacity_props.values_mut() {
3362            store.remove(entity);
3363        }
3364    }
3365
3366    pub(crate) fn needs_restyle(&mut self, entity: Entity) {
3367        if entity == Entity::null() || self.restyle.contains(&entity) {
3368            return;
3369        }
3370        self.restyle.insert(entity);
3371    }
3372
3373    pub(crate) fn needs_relayout(&mut self, entity: Entity) {
3374        self.relayout.insert(entity);
3375    }
3376
3377    pub(crate) fn needs_access_update(&mut self, entity: Entity) {
3378        self.reaccess.insert(entity);
3379    }
3380
3381    pub(crate) fn needs_text_update(&mut self, entity: Entity) {
3382        self.text_construction.insert(entity);
3383        self.text_layout.insert(entity);
3384    }
3385
3386    pub(crate) fn needs_text_layout(&mut self, entity: Entity) {
3387        self.text_layout.insert(entity);
3388    }
3389
3390    pub(crate) fn needs_retransform(&mut self, entity: Entity) {
3391        self.retransform.insert(entity);
3392    }
3393
3394    pub(crate) fn needs_reclip(&mut self, entity: Entity) {
3395        self.reclip.insert(entity);
3396    }
3397
3398    // pub fn should_redraw<F: FnOnce()>(&mut self, f: F) {
3399    //     if !self.redraw_list.is_empty() {
3400    //         f();
3401    //     }
3402    // }
3403
3404    // Remove all shared style data.
3405    pub(crate) fn clear_style_rules(&mut self) {
3406        self.disabled.clear_rules();
3407        // Display
3408        self.display.clear_rules();
3409        // Visibility
3410        self.visibility.clear_rules();
3411        // Opacity
3412        self.opacity.clear_rules();
3413        // Z Order
3414        self.z_index.clear_rules();
3415
3416        // Clipping
3417        self.clip_path.clear_rules();
3418
3419        // Filters
3420        self.filter.clear_rules();
3421        self.backdrop_filter.clear_rules();
3422
3423        // Blend Mode
3424        self.blend_mode.clear_rules();
3425
3426        // Transform
3427        self.transform.clear_rules();
3428        self.transform_origin.clear_rules();
3429        self.translate.clear_rules();
3430        self.rotate.clear_rules();
3431        self.scale.clear_rules();
3432
3433        self.overflowx.clear_rules();
3434        self.overflowy.clear_rules();
3435
3436        // Border widths
3437        self.border_top_width.clear_rules();
3438        self.border_right_width.clear_rules();
3439        self.border_bottom_width.clear_rules();
3440        self.border_left_width.clear_rules();
3441        // Border colors
3442        self.border_top_color.clear_rules();
3443        self.border_right_color.clear_rules();
3444        self.border_bottom_color.clear_rules();
3445        self.border_left_color.clear_rules();
3446        // Border styles
3447        self.border_top_style.clear_rules();
3448        self.border_right_style.clear_rules();
3449        self.border_bottom_style.clear_rules();
3450        self.border_left_style.clear_rules();
3451
3452        // Corner Shape
3453        self.corner_bottom_left_shape.clear_rules();
3454        self.corner_bottom_right_shape.clear_rules();
3455        self.corner_top_left_shape.clear_rules();
3456        self.corner_top_right_shape.clear_rules();
3457
3458        // Corner Radius
3459        self.corner_bottom_left_radius.clear_rules();
3460        self.corner_bottom_right_radius.clear_rules();
3461        self.corner_top_left_radius.clear_rules();
3462        self.corner_top_right_radius.clear_rules();
3463
3464        // Corner Smoothing
3465        self.corner_bottom_left_smoothing.clear_rules();
3466        self.corner_bottom_right_smoothing.clear_rules();
3467        self.corner_top_left_smoothing.clear_rules();
3468        self.corner_top_right_smoothing.clear_rules();
3469
3470        // Outline
3471        self.outline_width.clear_rules();
3472        self.outline_color.clear_rules();
3473        self.outline_offset.clear_rules();
3474
3475        // Background
3476        self.background_color.clear_rules();
3477        self.background_image.clear_rules();
3478        self.background_position.clear_rules();
3479        self.background_repeat.clear_rules();
3480        self.background_size.clear_rules();
3481
3482        self.shadow.clear_rules();
3483
3484        self.layout_type.clear_rules();
3485        self.position_type.clear_rules();
3486        self.alignment.clear_rules();
3487        self.direction.clear_rules();
3488        self.wrap.clear_rules();
3489
3490        // Grid
3491        self.grid_columns.clear_rules();
3492        self.grid_rows.clear_rules();
3493        self.column_start.clear_rules();
3494        self.column_span.clear_rules();
3495
3496        // Space
3497        self.left.clear_rules();
3498        self.right.clear_rules();
3499        self.top.clear_rules();
3500        self.bottom.clear_rules();
3501
3502        // Size
3503        self.width.clear_rules();
3504        self.height.clear_rules();
3505
3506        // Size Constraints
3507        self.min_width.clear_rules();
3508        self.max_width.clear_rules();
3509        self.min_height.clear_rules();
3510        self.max_height.clear_rules();
3511
3512        self.min_horizontal_gap.clear_rules();
3513        self.max_horizontal_gap.clear_rules();
3514        self.min_vertical_gap.clear_rules();
3515        self.max_vertical_gap.clear_rules();
3516
3517        // Padding
3518        self.padding_left.clear_rules();
3519        self.padding_right.clear_rules();
3520        self.padding_top.clear_rules();
3521        self.padding_bottom.clear_rules();
3522        self.horizontal_gap.clear_rules();
3523        self.vertical_gap.clear_rules();
3524
3525        // Text and Font
3526        self.text_wrap.clear_rules();
3527        self.text_overflow.clear_rules();
3528        self.letter_spacing.clear_rules();
3529        self.line_height.clear_rules();
3530        self.line_clamp.clear_rules();
3531        self.text_align.clear_rules();
3532        self.font_family.clear_rules();
3533        self.font_weight.clear_rules();
3534        self.font_slant.clear_rules();
3535        self.font_color.clear_rules();
3536        self.font_size.clear_rules();
3537        self.font_variation_settings.clear_rules();
3538        self.selection_color.clear_rules();
3539        self.caret_color.clear_rules();
3540        self.text_decoration_line.clear_rules();
3541        self.text_decoration_style.clear_rules();
3542        self.text_decoration_color.clear_rules();
3543        self.text_stroke_width.clear_rules();
3544        self.text_stroke_style.clear_rules();
3545
3546        self.cursor.clear_rules();
3547
3548        self.pointer_events.clear_rules();
3549
3550        self.name.clear_rules();
3551
3552        self.fill.clear_rules();
3553
3554        // Clear all custom property rule data on stylesheet reload
3555        for store in self.custom_color_props.values_mut() {
3556            store.clear_rules();
3557        }
3558        self.custom_color_props
3559            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3560        for store in self.custom_length_props.values_mut() {
3561            store.clear_rules();
3562        }
3563        self.custom_length_props
3564            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3565        for store in self.custom_font_size_props.values_mut() {
3566            store.clear_rules();
3567        }
3568        self.custom_font_size_props
3569            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3570        for store in self.custom_letter_spacing_props.values_mut() {
3571            store.clear_rules();
3572        }
3573        self.custom_letter_spacing_props
3574            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3575        for store in self.custom_line_height_props.values_mut() {
3576            store.clear_rules();
3577        }
3578        self.custom_line_height_props
3579            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3580        for store in self.custom_units_props.values_mut() {
3581            store.clear_rules();
3582        }
3583        self.custom_units_props
3584            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3585        for store in self.custom_opacity_props.values_mut() {
3586            store.clear_rules();
3587        }
3588        self.custom_opacity_props
3589            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
3590    }
3591}