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, BackgroundImage, BackgroundSize, BorderStyleKeyword, ClipPath, Color,
76    CornerShape, CssRule, CursorIcon, Direction, Display, Filter, FontFamily, FontSize, FontSlant,
77    FontVariation, FontWeight, FontWeightKeyword, FontWidth, GenericFontFamily, Gradient,
78    HorizontalPosition, HorizontalPositionKeyword, LayoutWrap, Length, LengthOrPercentage,
79    LengthValue, LineClamp, LineDirection, LinearGradient, Matrix, Opacity, Overflow,
80    PointerEvents, Position, PositionType, RGBA, Scale, Shadow, TextAlign, TextDecorationLine,
81    TextDecorationStyle, TextOverflow, TextStroke, TextStrokeStyle, Transform, Transition,
82    Translate, VerticalPosition, VerticalPositionKeyword, Visibility,
83};
84
85use cssparser::Token as CssToken;
86use vizia_style::{
87    BlendMode, EasingFunction, KeyframeSelector, ParserOptions, Property, Selectors, StyleSheet,
88    TokenList, TokenOrValue, Variable,
89};
90
91mod rule;
92pub(crate) use rule::Rule;
93
94mod pseudoclass;
95pub(crate) use pseudoclass::*;
96
97mod transform;
98pub(crate) use transform::*;
99
100use crate::animation::{AnimationState, Interpolator, Keyframe, TimingFunction};
101use crate::storage::animatable_set::AnimatableSet;
102use crate::storage::style_set::StyleSet;
103use bitflags::bitflags;
104use vizia_id::IdManager;
105use vizia_storage::SparseSet;
106
107bitflags! {
108    /// Describes the capabilities of a view with respect to user interaction.
109    #[derive(Debug, Clone, Copy)]
110    pub(crate) struct Abilities: u8 {
111        // Whether a view will be included in hit tests and receive mouse input events.
112        const HOVERABLE = 1 << 0;
113        // Whether a view can be focused to receive keyboard events.
114        const FOCUSABLE = 1 << 1;
115        // Whether a view can be checked.
116        const CHECKABLE = 1 << 2;
117        // Whether a view can be focused via keyboard navigation.
118        const NAVIGABLE = 1 << 3;
119        // Whether a view can be dragged during a drag and drop.
120        const DRAGGABLE = 1 << 4;
121    }
122}
123
124impl Default for Abilities {
125    fn default() -> Abilities {
126        Abilities::HOVERABLE
127    }
128}
129
130bitflags! {
131    pub(crate) struct SystemFlags: u8 {
132        const RELAYOUT = 1;
133        const RESTYLE = 1 << 1;
134        const REFLOW = 1 << 2;
135        const REDRAW = 1 << 3;
136        const RETRANSFORM = 1 << 4;
137        const RECLIP = 1 << 5;
138        const REACCESS = 1 << 6;
139    }
140}
141
142impl Default for SystemFlags {
143    fn default() -> Self {
144        SystemFlags::all()
145    }
146}
147
148/// An enum which represents an image or a gradient.
149#[derive(Debug, Clone, PartialEq)]
150pub enum ImageOrGradient {
151    /// Represents an image by name.
152    Image(String),
153    /// A gradient.
154    Gradient(Gradient),
155}
156
157/// A font-family.
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub enum FamilyOwned {
160    /// A generic font-family.
161    Generic(GenericFontFamily),
162    /// A named front-family.
163    Named(String),
164}
165
166impl AsRef<str> for FamilyOwned {
167    fn as_ref(&self) -> &str {
168        match self {
169            FamilyOwned::Generic(generic) => match generic {
170                GenericFontFamily::Serif => "serif",
171                GenericFontFamily::SansSerif => "sans-serif",
172                GenericFontFamily::Cursive => todo!(),
173                GenericFontFamily::Fantasy => todo!(),
174                GenericFontFamily::Monospace => "Cascadia Mono",
175            },
176            FamilyOwned::Named(family) => family.as_str(),
177        }
178    }
179}
180
181pub(crate) struct StyleRule {
182    pub(crate) selector: Selector<Selectors>,
183    /// The ancestor hashes associated with the selector.
184    pub(crate) hashes: AncestorHashes,
185}
186
187impl StyleRule {
188    pub(crate) fn new(selector: Selector<Selectors>) -> Self {
189        let hashes = AncestorHashes::new(&selector, vizia_style::QuirksMode::NoQuirks);
190        Self { selector, hashes }
191    }
192}
193
194/// Stores the style properties of all entities in the application.
195#[derive(Default)]
196pub struct Style {
197    pub(crate) rule_manager: IdManager<Rule>,
198
199    // Creates and destroys animation ids
200    pub(crate) animation_manager: IdManager<Animation>,
201    pub(crate) animations: HashMap<String, Animation>,
202    // List of animations to be started on the next frame
203    pub(crate) pending_animations: Vec<(Entity, Animation, Duration, Duration)>,
204
205    // List of rules
206    pub(crate) rules: IndexMap<Rule, StyleRule>,
207
208    pub(crate) default_font: Vec<FamilyOwned>,
209
210    // CSS Selector Properties
211    pub(crate) element: SparseSet<u32>,
212    pub(crate) ids: SparseSet<String>,
213    pub(crate) classes: SparseSet<HashSet<String>>,
214    pub(crate) pseudo_classes: SparseSet<PseudoClassFlags>,
215    pub(crate) disabled: StyleSet<bool>,
216    pub(crate) abilities: SparseSet<Abilities>,
217
218    // Accessibility Properties
219    pub(crate) name: StyleSet<String>,
220    pub(crate) role: SparseSet<Role>,
221    pub(crate) live: SparseSet<Live>,
222    pub(crate) labelled_by: SparseSet<String>,
223    pub(crate) described_by: SparseSet<String>,
224    pub(crate) controls: SparseSet<String>,
225    pub(crate) active_descendant: SparseSet<String>,
226    pub(crate) expanded: SparseSet<bool>,
227    pub(crate) selected: SparseSet<bool>,
228    pub(crate) hidden: SparseSet<bool>,
229    pub(crate) orientation: SparseSet<Orientation>,
230    pub(crate) text_value: SparseSet<String>,
231    pub(crate) numeric_value: SparseSet<f64>,
232
233    // Visibility
234    pub(crate) visibility: StyleSet<Visibility>,
235
236    // Opacity
237    pub(crate) opacity: AnimatableVarSet<Opacity>,
238
239    // Z Order
240    pub(crate) z_index: StyleSet<i32>,
241
242    // Clipping
243    pub(crate) clip_path: AnimatableSet<ClipPath>,
244
245    // Overflow
246    pub(crate) overflowx: StyleSet<Overflow>,
247    pub(crate) overflowy: StyleSet<Overflow>,
248
249    // Filters
250    pub(crate) filter: AnimatableSet<Filter>,
251    pub(crate) backdrop_filter: AnimatableSet<Filter>,
252
253    pub(crate) blend_mode: StyleSet<BlendMode>,
254
255    // Transform
256    pub(crate) transform: AnimatableSet<Vec<Transform>>,
257    pub(crate) transform_origin: AnimatableSet<Translate>,
258    pub(crate) translate: AnimatableSet<Translate>,
259    pub(crate) rotate: AnimatableSet<Angle>,
260    pub(crate) scale: AnimatableSet<Scale>,
261
262    // Border
263    pub(crate) border_width: AnimatableVarSet<LengthOrPercentage>,
264    pub(crate) border_color: AnimatableVarSet<Color>,
265    pub(crate) border_style: StyleSet<BorderStyleKeyword>,
266
267    // Corner Shape
268    pub(crate) corner_top_left_shape: StyleSet<CornerShape>,
269    pub(crate) corner_top_right_shape: StyleSet<CornerShape>,
270    pub(crate) corner_bottom_left_shape: StyleSet<CornerShape>,
271    pub(crate) corner_bottom_right_shape: StyleSet<CornerShape>,
272
273    // Corner Radius
274    pub(crate) corner_top_left_radius: AnimatableVarSet<LengthOrPercentage>,
275    pub(crate) corner_top_right_radius: AnimatableVarSet<LengthOrPercentage>,
276    pub(crate) corner_bottom_left_radius: AnimatableVarSet<LengthOrPercentage>,
277    pub(crate) corner_bottom_right_radius: AnimatableVarSet<LengthOrPercentage>,
278
279    // Corner Smoothing
280    pub(crate) corner_top_left_smoothing: AnimatableSet<f32>,
281    pub(crate) corner_top_right_smoothing: AnimatableSet<f32>,
282    pub(crate) corner_bottom_left_smoothing: AnimatableSet<f32>,
283    pub(crate) corner_bottom_right_smoothing: AnimatableSet<f32>,
284
285    // Outline
286    pub(crate) outline_width: AnimatableVarSet<LengthOrPercentage>,
287    pub(crate) outline_color: AnimatableVarSet<Color>,
288    pub(crate) outline_offset: AnimatableVarSet<LengthOrPercentage>,
289
290    // Background
291    pub(crate) background_color: AnimatableVarSet<Color>,
292    pub(crate) background_image: AnimatableSet<Vec<ImageOrGradient>>,
293    pub(crate) background_size: AnimatableSet<Vec<BackgroundSize>>,
294
295    // Shadow
296    pub(crate) shadow: AnimatableVarSet<Vec<Shadow>>,
297
298    // Text
299    pub(crate) text: SparseSet<String>,
300    pub(crate) text_wrap: StyleSet<bool>,
301    pub(crate) text_overflow: StyleSet<TextOverflow>,
302    pub(crate) line_clamp: StyleSet<LineClamp>,
303    pub(crate) text_align: StyleSet<TextAlign>,
304    pub(crate) text_decoration_line: StyleSet<TextDecorationLine>,
305    pub(crate) text_stroke_width: StyleSet<Length>,
306    pub(crate) text_stroke_style: StyleSet<TextStrokeStyle>,
307    pub(crate) underline_style: StyleSet<TextDecorationLine>,
308    pub(crate) overline_style: StyleSet<TextDecorationStyle>,
309    pub(crate) strikethrough_style: StyleSet<TextDecorationStyle>,
310    pub(crate) underline_color: AnimatableVarSet<Color>,
311    pub(crate) overline_color: AnimatableVarSet<Color>,
312    pub(crate) strikethrough_color: AnimatableVarSet<Color>,
313    pub(crate) font_family: StyleSet<Vec<FamilyOwned>>,
314    pub(crate) font_color: AnimatableVarSet<Color>,
315    pub(crate) font_size: AnimatableVarSet<FontSize>,
316    pub(crate) font_weight: StyleSet<FontWeight>,
317    pub(crate) font_slant: StyleSet<FontSlant>,
318    pub(crate) font_width: StyleSet<FontWidth>,
319    pub(crate) font_variation_settings: StyleSet<Vec<FontVariation>>,
320    pub(crate) caret_color: AnimatableVarSet<Color>,
321    pub(crate) selection_color: AnimatableVarSet<Color>,
322
323    pub(crate) fill: AnimatableVarSet<Color>,
324
325    // cursor Icon
326    pub(crate) cursor: StyleSet<CursorIcon>,
327
328    pub(crate) pointer_events: StyleSet<PointerEvents>,
329
330    // LAYOUT
331
332    // Display
333    pub(crate) display: AnimatableSet<Display>,
334
335    // Layout Type
336    pub(crate) layout_type: StyleSet<LayoutType>,
337
338    // Position
339    pub(crate) position_type: StyleSet<PositionType>,
340
341    pub(crate) alignment: StyleSet<Alignment>,
342    pub(crate) direction: StyleSet<Direction>,
343    pub(crate) wrap: StyleSet<LayoutWrap>,
344
345    // Grid
346    pub(crate) grid_columns: StyleSet<Vec<Units>>,
347    pub(crate) grid_rows: StyleSet<Vec<Units>>,
348
349    pub(crate) column_start: StyleSet<usize>,
350    pub(crate) column_span: StyleSet<usize>,
351    pub(crate) row_start: StyleSet<usize>,
352    pub(crate) row_span: StyleSet<usize>,
353
354    // Spacing
355    pub(crate) left: AnimatableVarSet<Units>,
356    pub(crate) right: AnimatableVarSet<Units>,
357    pub(crate) top: AnimatableVarSet<Units>,
358    pub(crate) bottom: AnimatableVarSet<Units>,
359
360    // Padding
361    pub(crate) padding_left: AnimatableVarSet<Units>,
362    pub(crate) padding_right: AnimatableVarSet<Units>,
363    pub(crate) padding_top: AnimatableVarSet<Units>,
364    pub(crate) padding_bottom: AnimatableVarSet<Units>,
365    pub(crate) vertical_gap: AnimatableVarSet<Units>,
366    pub(crate) horizontal_gap: AnimatableVarSet<Units>,
367
368    // Scrolling
369    pub(crate) vertical_scroll: AnimatableSet<f32>,
370    pub(crate) horizontal_scroll: AnimatableSet<f32>,
371
372    // Size
373    pub(crate) width: AnimatableVarSet<Units>,
374    pub(crate) height: AnimatableVarSet<Units>,
375
376    // Size Constraints
377    pub(crate) min_width: AnimatableVarSet<Units>,
378    pub(crate) max_width: AnimatableVarSet<Units>,
379    pub(crate) min_height: AnimatableVarSet<Units>,
380    pub(crate) max_height: AnimatableVarSet<Units>,
381
382    // Gap Constraints
383    pub(crate) min_horizontal_gap: AnimatableVarSet<Units>,
384    pub(crate) max_horizontal_gap: AnimatableVarSet<Units>,
385    pub(crate) min_vertical_gap: AnimatableVarSet<Units>,
386    pub(crate) max_vertical_gap: AnimatableVarSet<Units>,
387
388    pub(crate) system_flags: SystemFlags,
389
390    pub(crate) restyle: HashSet<Entity>,
391    pub(crate) text_construction: HashSet<Entity>,
392    pub(crate) text_layout: HashSet<Entity>,
393    pub(crate) reaccess: HashSet<Entity>,
394    pub(crate) retransform: HashSet<Entity>,
395    pub(crate) reclip: HashSet<Entity>,
396
397    pub(crate) text_range: SparseSet<Range<usize>>,
398    pub(crate) text_span: SparseSet<bool>,
399
400    /// This includes both the system's HiDPI scaling factor as well as `cx.user_scale_factor`.
401    pub(crate) dpi_factor: f64,
402
403    pub(crate) custom_color_props: HashMap<u64, AnimatableVarSet<Color>>,
404    pub(crate) custom_length_props: HashMap<u64, AnimatableVarSet<LengthOrPercentage>>,
405    pub(crate) custom_font_size_props: HashMap<u64, AnimatableVarSet<FontSize>>,
406    pub(crate) custom_units_props: HashMap<u64, AnimatableVarSet<Units>>,
407    pub(crate) custom_opacity_props: HashMap<u64, AnimatableVarSet<Opacity>>,
408    pub(crate) custom_shadow_props: HashMap<u64, AnimatableVarSet<Vec<Shadow>>>,
409}
410
411impl Style {
412    /// Returns the scale factor of the application.
413    pub fn scale_factor(&self) -> f32 {
414        self.dpi_factor as f32
415    }
416
417    /// Function to convert logical points to physical pixels.
418    pub fn logical_to_physical(&self, logical: f32) -> f32 {
419        (logical * self.dpi_factor as f32).round()
420    }
421
422    /// Function to convert physical pixels to logical points.
423    pub fn physical_to_logical(&self, physical: f32) -> f32 {
424        physical / self.dpi_factor as f32
425    }
426
427    pub(crate) fn remove_rules(&mut self) {
428        self.rule_manager.reset();
429        self.rules.clear();
430    }
431
432    pub(crate) fn get_animation(&self, name: &str) -> Option<&Animation> {
433        self.animations.get(name)
434    }
435
436    pub(crate) fn add_keyframe(
437        &mut self,
438        animation_id: Animation,
439        time: f32,
440        properties: &[Property],
441    ) {
442        fn insert_keyframe<T: 'static + Interpolator + Debug + Clone + PartialEq + Default>(
443            storage: &mut AnimatableSet<T>,
444            animation_id: Animation,
445            time: f32,
446            value: T,
447        ) {
448            let keyframe = Keyframe { time, value, timing_function: TimingFunction::linear() };
449
450            if let Some(anim_state) = storage.get_animation_mut(animation_id) {
451                anim_state.keyframes.push(keyframe)
452            } else {
453                let anim_state = AnimationState::new(animation_id).with_keyframe(keyframe);
454                storage.insert_animation(animation_id, anim_state);
455            }
456        }
457
458        fn insert_keyframe2<T: 'static + Interpolator + Debug + Clone + PartialEq + Default>(
459            storage: &mut AnimatableVarSet<T>,
460            animation_id: Animation,
461            time: f32,
462            value: T,
463        ) {
464            let keyframe = Keyframe { time, value, timing_function: TimingFunction::linear() };
465
466            if let Some(anim_state) = storage.get_animation_mut(animation_id) {
467                anim_state.keyframes.push(keyframe)
468            } else {
469                let anim_state = AnimationState::new(animation_id).with_keyframe(keyframe);
470                storage.insert_animation(animation_id, anim_state);
471            }
472        }
473
474        for property in properties.iter() {
475            match property {
476                // DISPLAY
477                Property::Display(value) => {
478                    insert_keyframe(&mut self.display, animation_id, time, *value);
479                }
480
481                Property::Opacity(value) => {
482                    insert_keyframe2(&mut self.opacity, animation_id, time, *value);
483                }
484
485                Property::ClipPath(value) => {
486                    insert_keyframe(&mut self.clip_path, animation_id, time, value.clone());
487                }
488
489                // TRANSFORM
490                Property::Transform(value) => {
491                    insert_keyframe(&mut self.transform, animation_id, time, value.clone());
492                }
493
494                Property::TransformOrigin(transform_origin) => {
495                    let x = transform_origin.x.to_length_or_percentage();
496                    let y = transform_origin.y.to_length_or_percentage();
497                    let value = Translate { x, y };
498                    insert_keyframe(&mut self.transform_origin, animation_id, time, value);
499                }
500
501                Property::Translate(value) => {
502                    insert_keyframe(&mut self.translate, animation_id, time, value.clone());
503                }
504
505                Property::Rotate(value) => {
506                    insert_keyframe(&mut self.rotate, animation_id, time, *value);
507                }
508
509                Property::Scale(value) => {
510                    insert_keyframe(&mut self.scale, animation_id, time, *value);
511                }
512
513                // BORDER
514                Property::BorderWidth(value) => {
515                    insert_keyframe2(
516                        &mut self.border_width,
517                        animation_id,
518                        time,
519                        value.left.0.clone(),
520                    );
521                }
522
523                Property::BorderColor(value) => {
524                    insert_keyframe2(&mut self.border_color, animation_id, time, *value);
525                }
526
527                Property::CornerTopLeftRadius(value) => {
528                    insert_keyframe2(
529                        &mut self.corner_top_left_radius,
530                        animation_id,
531                        time,
532                        value.clone(),
533                    );
534                }
535
536                Property::CornerTopRightRadius(value) => {
537                    insert_keyframe2(
538                        &mut self.corner_top_right_radius,
539                        animation_id,
540                        time,
541                        value.clone(),
542                    );
543                }
544
545                Property::CornerBottomLeftRadius(value) => {
546                    insert_keyframe2(
547                        &mut self.corner_bottom_left_radius,
548                        animation_id,
549                        time,
550                        value.clone(),
551                    );
552                }
553
554                Property::CornerBottomRightRadius(value) => {
555                    insert_keyframe2(
556                        &mut self.corner_bottom_right_radius,
557                        animation_id,
558                        time,
559                        value.clone(),
560                    );
561                }
562
563                // OUTLINE
564                Property::OutlineWidth(value) => {
565                    insert_keyframe2(
566                        &mut self.outline_width,
567                        animation_id,
568                        time,
569                        value.left.0.clone(),
570                    );
571                }
572
573                Property::OutlineColor(value) => {
574                    insert_keyframe2(&mut self.outline_color, animation_id, time, *value);
575                }
576
577                Property::OutlineOffset(value) => {
578                    insert_keyframe2(&mut self.outline_offset, animation_id, time, value.clone());
579                }
580
581                // BACKGROUND
582                Property::BackgroundColor(value) => {
583                    insert_keyframe2(&mut self.background_color, animation_id, time, *value);
584                }
585
586                Property::BackgroundImage(images) => {
587                    let images = images
588                        .iter()
589                        .filter_map(|img| match img {
590                            BackgroundImage::None => None,
591                            BackgroundImage::Gradient(gradient) => {
592                                Some(ImageOrGradient::Gradient(*gradient.clone()))
593                            }
594                            BackgroundImage::Url(url) => {
595                                Some(ImageOrGradient::Image(url.url.to_string()))
596                            }
597                        })
598                        .collect::<Vec<_>>();
599                    insert_keyframe(&mut self.background_image, animation_id, time, images);
600                }
601
602                Property::BackgroundSize(value) => {
603                    insert_keyframe(&mut self.background_size, animation_id, time, value.clone());
604                }
605
606                // BOX SHADOW
607                Property::Shadow(value) => {
608                    insert_keyframe2(&mut self.shadow, animation_id, time, value.clone());
609                }
610
611                // TEXT
612                Property::FontColor(value) => {
613                    insert_keyframe2(&mut self.font_color, animation_id, time, *value);
614                }
615
616                Property::FontSize(value) => {
617                    insert_keyframe2(&mut self.font_size, animation_id, time, value.clone());
618                }
619
620                Property::CaretColor(value) => {
621                    insert_keyframe2(&mut self.caret_color, animation_id, time, *value);
622                }
623
624                Property::SelectionColor(value) => {
625                    insert_keyframe2(&mut self.selection_color, animation_id, time, *value);
626                }
627
628                // SPACE
629                Property::Left(value) => {
630                    insert_keyframe2(&mut self.left, animation_id, time, *value);
631                }
632
633                Property::Right(value) => {
634                    insert_keyframe2(&mut self.right, animation_id, time, *value);
635                }
636
637                Property::Top(value) => {
638                    insert_keyframe2(&mut self.top, animation_id, time, *value);
639                }
640
641                Property::Bottom(value) => {
642                    insert_keyframe2(&mut self.bottom, animation_id, time, *value);
643                }
644
645                // Padding
646                Property::PaddingLeft(value) => {
647                    insert_keyframe2(&mut self.padding_left, animation_id, time, *value);
648                }
649
650                Property::PaddingRight(value) => {
651                    insert_keyframe2(&mut self.padding_right, animation_id, time, *value);
652                }
653
654                Property::PaddingTop(value) => {
655                    insert_keyframe2(&mut self.padding_top, animation_id, time, *value);
656                }
657
658                Property::PaddingBottom(value) => {
659                    insert_keyframe2(&mut self.padding_bottom, animation_id, time, *value);
660                }
661
662                Property::HorizontalGap(value) => {
663                    insert_keyframe2(&mut self.horizontal_gap, animation_id, time, *value);
664                }
665
666                Property::VerticalGap(value) => {
667                    insert_keyframe2(&mut self.vertical_gap, animation_id, time, *value);
668                }
669
670                Property::Gap(value) => {
671                    insert_keyframe2(&mut self.horizontal_gap, animation_id, time, *value);
672                    insert_keyframe2(&mut self.vertical_gap, animation_id, time, *value);
673                }
674
675                // GAP CONSSTRAINTS
676                Property::MinGap(value) => {
677                    insert_keyframe2(&mut self.min_horizontal_gap, animation_id, time, *value);
678                    insert_keyframe2(&mut self.min_vertical_gap, animation_id, time, *value);
679                }
680
681                Property::MaxGap(value) => {
682                    insert_keyframe2(&mut self.max_horizontal_gap, animation_id, time, *value);
683                    insert_keyframe2(&mut self.max_vertical_gap, animation_id, time, *value);
684                }
685
686                Property::MinHorizontalGap(value) => {
687                    insert_keyframe2(&mut self.min_horizontal_gap, animation_id, time, *value);
688                }
689
690                Property::MaxHorizontalGap(value) => {
691                    insert_keyframe2(&mut self.max_horizontal_gap, animation_id, time, *value);
692                }
693
694                Property::MinVerticalGap(value) => {
695                    insert_keyframe2(&mut self.min_vertical_gap, animation_id, time, *value);
696                }
697
698                Property::MaxVerticalGap(value) => {
699                    insert_keyframe2(&mut self.max_vertical_gap, animation_id, time, *value);
700                }
701
702                // SIZE
703                Property::Width(value) => {
704                    insert_keyframe2(&mut self.width, animation_id, time, *value);
705                }
706
707                Property::Height(value) => {
708                    insert_keyframe2(&mut self.height, animation_id, time, *value);
709                }
710
711                // SIZE CONSTRAINTS
712                Property::MinWidth(value) => {
713                    insert_keyframe2(&mut self.min_width, animation_id, time, *value);
714                }
715
716                Property::MaxWidth(value) => {
717                    insert_keyframe2(&mut self.max_width, animation_id, time, *value);
718                }
719
720                Property::MinHeight(value) => {
721                    insert_keyframe2(&mut self.min_height, animation_id, time, *value);
722                }
723
724                Property::MaxHeight(value) => {
725                    insert_keyframe2(&mut self.max_height, animation_id, time, *value);
726                }
727
728                Property::UnderlineColor(value) => {
729                    insert_keyframe2(&mut self.underline_color, animation_id, time, *value);
730                }
731
732                Property::Fill(value) => {
733                    insert_keyframe2(&mut self.fill, animation_id, time, *value);
734                }
735
736                _ => {}
737            }
738        }
739    }
740
741    pub(crate) fn add_animation(&mut self, animation: AnimationBuilder) -> Animation {
742        let animation_id = self.animation_manager.create();
743        for keyframe in animation.keyframes.iter() {
744            self.add_keyframe(animation_id, keyframe.time, &keyframe.properties);
745        }
746
747        animation_id
748    }
749
750    pub(crate) fn enqueue_animation(
751        &mut self,
752        entity: Entity,
753        animation: Animation,
754        duration: Duration,
755        delay: Duration,
756    ) {
757        self.pending_animations.push((entity, animation, duration, delay));
758    }
759
760    pub(crate) fn play_pending_animations(&mut self) {
761        let start_time = Instant::now();
762
763        let pending_animations = self.pending_animations.drain(..).collect::<Vec<_>>();
764
765        for (entity, animation, duration, delay) in pending_animations {
766            self.play_animation(entity, animation, start_time + delay, duration, delay)
767        }
768    }
769
770    pub(crate) fn play_animation(
771        &mut self,
772        entity: Entity,
773        animation: Animation,
774        start_time: Instant,
775        duration: Duration,
776        delay: Duration,
777    ) {
778        self.display.play_animation(entity, animation, start_time, duration, delay);
779        self.opacity.play_animation(entity, animation, start_time, duration, delay);
780        self.clip_path.play_animation(entity, animation, start_time, duration, delay);
781
782        self.transform.play_animation(entity, animation, start_time, duration, delay);
783        self.transform_origin.play_animation(entity, animation, start_time, duration, delay);
784        self.translate.play_animation(entity, animation, start_time, duration, delay);
785        self.rotate.play_animation(entity, animation, start_time, duration, delay);
786        self.scale.play_animation(entity, animation, start_time, duration, delay);
787
788        self.border_width.play_animation(entity, animation, start_time, duration, delay);
789        self.border_color.play_animation(entity, animation, start_time, duration, delay);
790
791        self.corner_top_left_radius.play_animation(entity, animation, start_time, duration, delay);
792        self.corner_top_right_radius.play_animation(entity, animation, start_time, duration, delay);
793        self.corner_bottom_left_radius
794            .play_animation(entity, animation, start_time, duration, delay);
795        self.corner_bottom_right_radius
796            .play_animation(entity, animation, start_time, duration, delay);
797
798        self.outline_width.play_animation(entity, animation, start_time, duration, delay);
799        self.outline_color.play_animation(entity, animation, start_time, duration, delay);
800        self.outline_offset.play_animation(entity, animation, start_time, duration, delay);
801
802        self.background_color.play_animation(entity, animation, start_time, duration, delay);
803        self.background_image.play_animation(entity, animation, start_time, duration, delay);
804        self.background_size.play_animation(entity, animation, start_time, duration, delay);
805
806        self.shadow.play_animation(entity, animation, start_time, duration, delay);
807
808        self.font_color.play_animation(entity, animation, start_time, duration, delay);
809        self.font_size.play_animation(entity, animation, start_time, duration, delay);
810        self.caret_color.play_animation(entity, animation, start_time, duration, delay);
811        self.selection_color.play_animation(entity, animation, start_time, duration, delay);
812
813        self.left.play_animation(entity, animation, start_time, duration, delay);
814        self.right.play_animation(entity, animation, start_time, duration, delay);
815        self.top.play_animation(entity, animation, start_time, duration, delay);
816        self.bottom.play_animation(entity, animation, start_time, duration, delay);
817
818        self.padding_left.play_animation(entity, animation, start_time, duration, delay);
819        self.padding_right.play_animation(entity, animation, start_time, duration, delay);
820        self.padding_top.play_animation(entity, animation, start_time, duration, delay);
821        self.padding_bottom.play_animation(entity, animation, start_time, duration, delay);
822        self.horizontal_gap.play_animation(entity, animation, start_time, duration, delay);
823        self.vertical_gap.play_animation(entity, animation, start_time, duration, delay);
824
825        self.width.play_animation(entity, animation, start_time, duration, delay);
826        self.height.play_animation(entity, animation, start_time, duration, delay);
827
828        self.min_width.play_animation(entity, animation, start_time, duration, delay);
829        self.max_width.play_animation(entity, animation, start_time, duration, delay);
830        self.min_height.play_animation(entity, animation, start_time, duration, delay);
831        self.max_height.play_animation(entity, animation, start_time, duration, delay);
832
833        self.min_horizontal_gap.play_animation(entity, animation, start_time, duration, delay);
834        self.max_horizontal_gap.play_animation(entity, animation, start_time, duration, delay);
835        self.min_vertical_gap.play_animation(entity, animation, start_time, duration, delay);
836        self.max_vertical_gap.play_animation(entity, animation, start_time, duration, delay);
837
838        self.underline_color.play_animation(entity, animation, start_time, duration, delay);
839
840        self.fill.play_animation(entity, animation, start_time, duration, delay);
841
842        // Play animations on custom color properties
843        for store in self.custom_color_props.values_mut() {
844            store.play_animation(entity, animation, start_time, duration, delay);
845        }
846        // Play animations on custom length properties
847        for store in self.custom_length_props.values_mut() {
848            store.play_animation(entity, animation, start_time, duration, delay);
849        }
850        // Play animations on custom units properties
851        for store in self.custom_units_props.values_mut() {
852            store.play_animation(entity, animation, start_time, duration, delay);
853        }
854        // Play animations on custom opacity properties
855        for store in self.custom_opacity_props.values_mut() {
856            store.play_animation(entity, animation, start_time, duration, delay);
857        }
858        // Play animations on custom shadow properties
859        for store in self.custom_shadow_props.values_mut() {
860            store.play_animation(entity, animation, start_time, duration, delay);
861        }
862    }
863
864    pub(crate) fn is_animating(&self, entity: Entity, animation: Animation) -> bool {
865        self.display.has_active_animation(entity, animation)
866            | self.opacity.has_active_animation(entity, animation)
867            | self.clip_path.has_active_animation(entity, animation)
868            | self.transform.has_active_animation(entity, animation)
869            | self.transform_origin.has_active_animation(entity, animation)
870            | self.translate.has_active_animation(entity, animation)
871            | self.rotate.has_active_animation(entity, animation)
872            | self.scale.has_active_animation(entity, animation)
873            | self.border_width.has_active_animation(entity, animation)
874            | self.border_color.has_active_animation(entity, animation)
875            | self.corner_top_left_radius.has_active_animation(entity, animation)
876            | self.corner_top_right_radius.has_active_animation(entity, animation)
877            | self.corner_bottom_left_radius.has_active_animation(entity, animation)
878            | self.corner_bottom_right_radius.has_active_animation(entity, animation)
879            | self.outline_width.has_active_animation(entity, animation)
880            | self.outline_color.has_active_animation(entity, animation)
881            | self.outline_offset.has_active_animation(entity, animation)
882            | self.background_color.has_active_animation(entity, animation)
883            | self.background_image.has_active_animation(entity, animation)
884            | self.background_size.has_active_animation(entity, animation)
885            | self.shadow.has_active_animation(entity, animation)
886            | self.font_color.has_active_animation(entity, animation)
887            | self.font_size.has_active_animation(entity, animation)
888            | self.caret_color.has_active_animation(entity, animation)
889            | self.selection_color.has_active_animation(entity, animation)
890            | self.left.has_active_animation(entity, animation)
891            | self.right.has_active_animation(entity, animation)
892            | self.top.has_active_animation(entity, animation)
893            | self.bottom.has_active_animation(entity, animation)
894            | self.padding_left.has_active_animation(entity, animation)
895            | self.padding_right.has_active_animation(entity, animation)
896            | self.padding_top.has_active_animation(entity, animation)
897            | self.padding_bottom.has_active_animation(entity, animation)
898            | self.horizontal_gap.has_active_animation(entity, animation)
899            | self.vertical_gap.has_active_animation(entity, animation)
900            | self.width.has_active_animation(entity, animation)
901            | self.height.has_active_animation(entity, animation)
902            | self.min_width.has_active_animation(entity, animation)
903            | self.max_width.has_active_animation(entity, animation)
904            | self.min_height.has_active_animation(entity, animation)
905            | self.max_height.has_active_animation(entity, animation)
906            | self.min_horizontal_gap.has_active_animation(entity, animation)
907            | self.max_horizontal_gap.has_active_animation(entity, animation)
908            | self.min_vertical_gap.has_active_animation(entity, animation)
909            | self.max_vertical_gap.has_active_animation(entity, animation)
910            | self.underline_color.has_active_animation(entity, animation)
911            | self.fill.has_active_animation(entity, animation)
912    }
913
914    pub(crate) fn parse_theme(&mut self, stylesheet: &str) {
915        if let Ok(stylesheet) = StyleSheet::parse(stylesheet, ParserOptions::new()) {
916            let rules = stylesheet.rules.0;
917
918            for rule in rules {
919                match rule {
920                    CssRule::Style(style_rule) => {
921                        // let selectors = style_rule.selectors;
922
923                        for selector in style_rule.selectors.slice() {
924                            let rule_id = self.rule_manager.create();
925
926                            for property in style_rule.declarations.declarations.iter() {
927                                match property {
928                                    Property::Transition(transitions) => {
929                                        for transition in transitions.iter() {
930                                            self.insert_transition(rule_id, transition);
931                                        }
932                                    }
933
934                                    _ => {
935                                        self.insert_property(rule_id, property);
936                                    }
937                                }
938                            }
939
940                            self.rules.insert(rule_id, StyleRule::new(selector.clone()));
941                        }
942                    }
943
944                    CssRule::Keyframes(keyframes_rule) => {
945                        let name = keyframes_rule.name.as_string();
946
947                        let animation_id = self.animation_manager.create();
948
949                        for keyframes in keyframes_rule.keyframes {
950                            for selector in keyframes.selectors.iter() {
951                                let time = match selector {
952                                    KeyframeSelector::From => 0.0,
953                                    KeyframeSelector::To => 1.0,
954                                    KeyframeSelector::Percentage(percentage) => {
955                                        percentage.0 / 100.0
956                                    }
957                                };
958
959                                self.add_keyframe(
960                                    animation_id,
961                                    time,
962                                    &keyframes.declarations.declarations,
963                                );
964                            }
965                        }
966
967                        self.animations.insert(name, animation_id);
968                    }
969
970                    _ => {}
971                }
972            }
973        } else {
974            println!("Failed to parse stylesheet");
975        }
976    }
977
978    fn insert_transition(&mut self, rule_id: Rule, transition: &Transition) {
979        let animation = self.animation_manager.create();
980        match transition.property.as_ref() {
981            "display" => {
982                self.display.insert_animation(animation, self.add_transition(transition));
983                self.display.insert_transition(rule_id, animation);
984            }
985
986            "opacity" => {
987                self.opacity.insert_animation(animation, self.add_transition(transition));
988                self.opacity.insert_transition(rule_id, animation);
989            }
990
991            "clip-path" => {
992                self.clip_path.insert_animation(animation, self.add_transition(transition));
993                self.clip_path.insert_transition(rule_id, animation);
994            }
995
996            "transform" => {
997                self.transform.insert_animation(animation, self.add_transition(transition));
998                self.transform.insert_transition(rule_id, animation);
999            }
1000
1001            "transform-origin" => {
1002                self.transform_origin.insert_animation(animation, self.add_transition(transition));
1003                self.transform_origin.insert_transition(rule_id, animation);
1004            }
1005
1006            "translate" => {
1007                self.translate.insert_animation(animation, self.add_transition(transition));
1008                self.translate.insert_transition(rule_id, animation);
1009            }
1010
1011            "rotate" => {
1012                self.rotate.insert_animation(animation, self.add_transition(transition));
1013                self.rotate.insert_transition(rule_id, animation);
1014            }
1015
1016            "scale" => {
1017                self.scale.insert_animation(animation, self.add_transition(transition));
1018                self.scale.insert_transition(rule_id, animation);
1019            }
1020
1021            "border" => {
1022                self.border_width.insert_animation(animation, self.add_transition(transition));
1023                self.border_width.insert_transition(rule_id, animation);
1024                self.border_color.insert_animation(animation, self.add_transition(transition));
1025                self.border_color.insert_transition(rule_id, animation);
1026            }
1027
1028            "border-width" => {
1029                self.border_width.insert_animation(animation, self.add_transition(transition));
1030                self.border_width.insert_transition(rule_id, animation);
1031            }
1032
1033            "border-color" => {
1034                self.border_color.insert_animation(animation, self.add_transition(transition));
1035                self.border_color.insert_transition(rule_id, animation);
1036            }
1037
1038            "corner-radius" => {
1039                self.corner_bottom_left_radius
1040                    .insert_animation(animation, self.add_transition(transition));
1041                self.corner_bottom_left_radius.insert_transition(rule_id, animation);
1042                self.corner_bottom_right_radius
1043                    .insert_animation(animation, self.add_transition(transition));
1044                self.corner_bottom_right_radius.insert_transition(rule_id, animation);
1045                self.corner_top_left_radius
1046                    .insert_animation(animation, self.add_transition(transition));
1047                self.corner_top_left_radius.insert_transition(rule_id, animation);
1048                self.corner_top_right_radius
1049                    .insert_animation(animation, self.add_transition(transition));
1050                self.corner_top_right_radius.insert_transition(rule_id, animation);
1051            }
1052
1053            "corner-top-left-radius" => {
1054                self.corner_top_left_radius
1055                    .insert_animation(animation, self.add_transition(transition));
1056                self.corner_top_left_radius.insert_transition(rule_id, animation);
1057            }
1058
1059            "corner-top-right-radius" => {
1060                self.corner_top_right_radius
1061                    .insert_animation(animation, self.add_transition(transition));
1062                self.corner_top_right_radius.insert_transition(rule_id, animation);
1063            }
1064
1065            "corner-bottom-left-radius" => {
1066                self.corner_bottom_left_radius
1067                    .insert_animation(animation, self.add_transition(transition));
1068                self.corner_bottom_left_radius.insert_transition(rule_id, animation);
1069            }
1070
1071            "corner-bottom-right-radius" => {
1072                self.corner_bottom_right_radius
1073                    .insert_animation(animation, self.add_transition(transition));
1074                self.corner_bottom_right_radius.insert_transition(rule_id, animation);
1075            }
1076
1077            "outline" => {
1078                self.outline_width.insert_animation(animation, self.add_transition(transition));
1079                self.outline_width.insert_transition(rule_id, animation);
1080                self.outline_color.insert_animation(animation, self.add_transition(transition));
1081                self.outline_color.insert_transition(rule_id, animation);
1082            }
1083
1084            "outline-width" => {
1085                self.outline_width.insert_animation(animation, self.add_transition(transition));
1086                self.outline_width.insert_transition(rule_id, animation);
1087            }
1088
1089            "outline-color" => {
1090                self.outline_color.insert_animation(animation, self.add_transition(transition));
1091                self.outline_color.insert_transition(rule_id, animation);
1092            }
1093
1094            "outline-offset" => {
1095                self.outline_offset.insert_animation(animation, self.add_transition(transition));
1096                self.outline_offset.insert_transition(rule_id, animation);
1097            }
1098
1099            "background-color" => {
1100                self.background_color.insert_animation(animation, self.add_transition(transition));
1101                self.background_color.insert_transition(rule_id, animation);
1102            }
1103
1104            "background-image" => {
1105                self.background_image.insert_animation(animation, self.add_transition(transition));
1106                self.background_image.insert_transition(rule_id, animation);
1107            }
1108
1109            "background-size" => {
1110                self.background_size.insert_animation(animation, self.add_transition(transition));
1111                self.background_size.insert_transition(rule_id, animation);
1112            }
1113
1114            "shadow" => {
1115                self.shadow.insert_animation(animation, self.add_transition(transition));
1116                self.shadow.insert_transition(rule_id, animation);
1117            }
1118
1119            "color" => {
1120                self.font_color.insert_animation(animation, self.add_transition(transition));
1121                self.font_color.insert_transition(rule_id, animation);
1122            }
1123
1124            "font-size" => {
1125                self.font_size.insert_animation(animation, self.add_transition(transition));
1126                self.font_size.insert_transition(rule_id, animation);
1127            }
1128
1129            "caret-color" => {
1130                self.caret_color.insert_animation(animation, self.add_transition(transition));
1131                self.caret_color.insert_transition(rule_id, animation);
1132            }
1133
1134            "selection-color" => {
1135                self.selection_color.insert_animation(animation, self.add_transition(transition));
1136                self.selection_color.insert_transition(rule_id, animation);
1137            }
1138
1139            "left" => {
1140                self.left.insert_animation(animation, self.add_transition(transition));
1141                self.left.insert_transition(rule_id, animation);
1142            }
1143
1144            "right" => {
1145                self.right.insert_animation(animation, self.add_transition(transition));
1146                self.right.insert_transition(rule_id, animation);
1147            }
1148
1149            "top" => {
1150                self.top.insert_animation(animation, self.add_transition(transition));
1151                self.top.insert_transition(rule_id, animation);
1152            }
1153
1154            "bottom" => {
1155                self.bottom.insert_animation(animation, self.add_transition(transition));
1156                self.bottom.insert_transition(rule_id, animation);
1157            }
1158
1159            "padding-left" => {
1160                self.padding_left.insert_animation(animation, self.add_transition(transition));
1161                self.padding_left.insert_transition(rule_id, animation);
1162            }
1163
1164            "padding-right" => {
1165                self.padding_right.insert_animation(animation, self.add_transition(transition));
1166                self.padding_right.insert_transition(rule_id, animation);
1167            }
1168
1169            "padding-top" => {
1170                self.padding_top.insert_animation(animation, self.add_transition(transition));
1171                self.padding_top.insert_transition(rule_id, animation);
1172            }
1173
1174            "padding-bottom" => {
1175                self.padding_bottom.insert_animation(animation, self.add_transition(transition));
1176                self.padding_bottom.insert_transition(rule_id, animation);
1177            }
1178
1179            "horizontal-gap" => {
1180                self.horizontal_gap.insert_animation(animation, self.add_transition(transition));
1181                self.horizontal_gap.insert_transition(rule_id, animation);
1182            }
1183
1184            "vertical-gap" => {
1185                self.vertical_gap.insert_animation(animation, self.add_transition(transition));
1186                self.vertical_gap.insert_transition(rule_id, animation);
1187            }
1188
1189            "gap" => {
1190                self.horizontal_gap.insert_animation(animation, self.add_transition(transition));
1191                self.horizontal_gap.insert_transition(rule_id, animation);
1192                self.vertical_gap.insert_animation(animation, self.add_transition(transition));
1193                self.vertical_gap.insert_transition(rule_id, animation);
1194            }
1195
1196            "width" => {
1197                self.width.insert_animation(animation, self.add_transition(transition));
1198                self.width.insert_transition(rule_id, animation);
1199            }
1200
1201            "height" => {
1202                self.height.insert_animation(animation, self.add_transition(transition));
1203                self.height.insert_transition(rule_id, animation);
1204            }
1205
1206            "min-width" => {
1207                self.min_width.insert_animation(animation, self.add_transition(transition));
1208                self.min_width.insert_transition(rule_id, animation);
1209            }
1210
1211            "max-width" => {
1212                self.max_width.insert_animation(animation, self.add_transition(transition));
1213                self.max_width.insert_transition(rule_id, animation);
1214            }
1215
1216            "min-height" => {
1217                self.min_height.insert_animation(animation, self.add_transition(transition));
1218                self.min_height.insert_transition(rule_id, animation);
1219            }
1220
1221            "max-height" => {
1222                self.max_height.insert_animation(animation, self.add_transition(transition));
1223                self.max_height.insert_transition(rule_id, animation);
1224            }
1225
1226            "min-horizontal-gap" => {
1227                self.min_horizontal_gap
1228                    .insert_animation(animation, self.add_transition(transition));
1229                self.min_horizontal_gap.insert_transition(rule_id, animation);
1230            }
1231
1232            "max-horizontal-gap" => {
1233                self.max_horizontal_gap
1234                    .insert_animation(animation, self.add_transition(transition));
1235                self.max_horizontal_gap.insert_transition(rule_id, animation);
1236            }
1237
1238            "min-vertical-gap" => {
1239                self.min_vertical_gap.insert_animation(animation, self.add_transition(transition));
1240                self.min_vertical_gap.insert_transition(rule_id, animation);
1241            }
1242
1243            "max-vertical-gap" => {
1244                self.max_vertical_gap.insert_animation(animation, self.add_transition(transition));
1245                self.max_vertical_gap.insert_transition(rule_id, animation);
1246            }
1247
1248            "underline-color" => {
1249                self.underline_color.insert_animation(animation, self.add_transition(transition));
1250                self.underline_color.insert_transition(rule_id, animation);
1251            }
1252
1253            "fill" => {
1254                self.fill.insert_animation(animation, self.add_transition(transition));
1255                self.fill.insert_transition(rule_id, animation);
1256            }
1257
1258            property_name if property_name.starts_with("--") => {
1259                let mut s = DefaultHasher::new();
1260                property_name.hash(&mut s);
1261                let variable_name_hash = s.finish();
1262                // Pre-compute one typed AnimationState per store before taking any mutable
1263                // borrows (add_transition takes &self so this is fine).
1264                let anim_color: AnimationState<Color> = self.add_transition(transition);
1265                let anim_length: AnimationState<LengthOrPercentage> =
1266                    self.add_transition(transition);
1267                let anim_font_size: AnimationState<FontSize> = self.add_transition(transition);
1268                let anim_units: AnimationState<Units> = self.add_transition(transition);
1269                let anim_opacity: AnimationState<Opacity> = self.add_transition(transition);
1270
1271                // Register in every custom-property store so whichever store the variable's
1272                // concrete value ends up in will actually animate.
1273                if let Some(store) = self.custom_color_props.get_mut(&variable_name_hash) {
1274                    store.insert_animation(animation, anim_color);
1275                    store.insert_transition(rule_id, animation);
1276                } else {
1277                    let mut store = AnimatableVarSet::default();
1278                    store.insert_animation(animation, anim_color);
1279                    store.insert_transition(rule_id, animation);
1280                    self.custom_color_props.insert(variable_name_hash, store);
1281                }
1282
1283                if let Some(store) = self.custom_length_props.get_mut(&variable_name_hash) {
1284                    store.insert_animation(animation, anim_length);
1285                    store.insert_transition(rule_id, animation);
1286                } else {
1287                    let mut store = AnimatableVarSet::default();
1288                    store.insert_animation(animation, anim_length);
1289                    store.insert_transition(rule_id, animation);
1290                    self.custom_length_props.insert(variable_name_hash, store);
1291                }
1292
1293                if let Some(store) = self.custom_font_size_props.get_mut(&variable_name_hash) {
1294                    store.insert_animation(animation, anim_font_size);
1295                    store.insert_transition(rule_id, animation);
1296                } else {
1297                    let mut store = AnimatableVarSet::default();
1298                    store.insert_animation(animation, anim_font_size);
1299                    store.insert_transition(rule_id, animation);
1300                    self.custom_font_size_props.insert(variable_name_hash, store);
1301                }
1302
1303                if let Some(store) = self.custom_units_props.get_mut(&variable_name_hash) {
1304                    store.insert_animation(animation, anim_units);
1305                    store.insert_transition(rule_id, animation);
1306                } else {
1307                    let mut store = AnimatableVarSet::default();
1308                    store.insert_animation(animation, anim_units);
1309                    store.insert_transition(rule_id, animation);
1310                    self.custom_units_props.insert(variable_name_hash, store);
1311                }
1312
1313                if let Some(store) = self.custom_opacity_props.get_mut(&variable_name_hash) {
1314                    store.insert_animation(animation, anim_opacity);
1315                    store.insert_transition(rule_id, animation);
1316                } else {
1317                    let mut store = AnimatableVarSet::default();
1318                    store.insert_animation(animation, anim_opacity);
1319                    store.insert_transition(rule_id, animation);
1320                    self.custom_opacity_props.insert(variable_name_hash, store);
1321                }
1322            }
1323
1324            _ => {}
1325        }
1326    }
1327
1328    fn insert_property(&mut self, rule_id: Rule, property: &Property) {
1329        fn variable_hash(var: &Variable<'_>) -> u64 {
1330            let mut s = DefaultHasher::new();
1331            var.name.hash(&mut s);
1332            s.finish()
1333        }
1334
1335        fn first_fallback_token<'i>(var: &'i Variable<'i>) -> Option<&'i TokenOrValue<'i>> {
1336            var.fallback.as_ref().and_then(|TokenList(tokens)| tokens.first())
1337        }
1338
1339        fn color_fallback(var: &Variable<'_>) -> Option<Color> {
1340            match first_fallback_token(var) {
1341                Some(TokenOrValue::Color(color)) => Some(*color),
1342                _ => None,
1343            }
1344        }
1345
1346        fn length_fallback(var: &Variable<'_>) -> Option<LengthOrPercentage> {
1347            match first_fallback_token(var) {
1348                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1349                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1350                {
1351                    Some(LengthOrPercentage::Length(Length::Value(LengthValue::Px(*value))))
1352                }
1353
1354                Some(TokenOrValue::Token(CssToken::Percentage { unit_value, .. })) => {
1355                    Some(LengthOrPercentage::Percentage(*unit_value * 100.0))
1356                }
1357
1358                _ => None,
1359            }
1360        }
1361
1362        fn font_size_fallback(var: &Variable<'_>) -> Option<FontSize> {
1363            match first_fallback_token(var) {
1364                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1365                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1366                {
1367                    Some(FontSize(Length::Value(LengthValue::Px(*value))))
1368                }
1369
1370                _ => None,
1371            }
1372        }
1373
1374        fn units_fallback(var: &Variable<'_>) -> Option<Units> {
1375            match first_fallback_token(var) {
1376                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1377                    if unit.as_ref().eq_ignore_ascii_case("px") =>
1378                {
1379                    Some(Units::Pixels(*value))
1380                }
1381
1382                Some(TokenOrValue::Token(CssToken::Dimension { value, unit, .. }))
1383                    if unit.as_ref().eq_ignore_ascii_case("s") =>
1384                {
1385                    Some(Units::Stretch(*value))
1386                }
1387
1388                Some(TokenOrValue::Token(CssToken::Ident(ident)))
1389                    if ident.as_ref().eq_ignore_ascii_case("auto") =>
1390                {
1391                    Some(Units::Auto)
1392                }
1393
1394                Some(TokenOrValue::Token(CssToken::Percentage { unit_value, .. })) => {
1395                    Some(Units::Percentage(*unit_value * 100.0))
1396                }
1397
1398                _ => None,
1399            }
1400        }
1401
1402        fn opacity_fallback(var: &Variable<'_>) -> Option<Opacity> {
1403            match first_fallback_token(var) {
1404                Some(TokenOrValue::Token(CssToken::Percentage { unit_value, .. })) => {
1405                    Some(Opacity(*unit_value))
1406                }
1407
1408                Some(TokenOrValue::Token(CssToken::Number { value, .. })) => Some(Opacity(*value)),
1409
1410                _ => None,
1411            }
1412        }
1413
1414        fn parse_shadow_list(tokens: &[TokenOrValue<'_>]) -> Option<Vec<Shadow>> {
1415            fn parse_shadow_length(token: &TokenOrValue<'_>) -> Option<Length> {
1416                match token {
1417                    TokenOrValue::Token(CssToken::Dimension { value, unit, .. })
1418                        if unit.as_ref().eq_ignore_ascii_case("px") =>
1419                    {
1420                        Some(Length::Value(LengthValue::Px(*value)))
1421                    }
1422
1423                    TokenOrValue::Token(CssToken::Number { value, .. }) if *value == 0.0 => {
1424                        Some(Length::Value(LengthValue::Px(0.0)))
1425                    }
1426
1427                    _ => None,
1428                }
1429            }
1430
1431            fn parse_single_shadow(tokens: &[TokenOrValue<'_>]) -> Option<Shadow> {
1432                let mut lengths: Vec<Length> = Vec::new();
1433                let mut color = None;
1434                let mut inset = false;
1435
1436                for token in tokens {
1437                    match token {
1438                        TokenOrValue::Token(CssToken::WhiteSpace(_)) => {}
1439
1440                        TokenOrValue::Color(c) => {
1441                            if color.is_some() {
1442                                return None;
1443                            }
1444                            color = Some(*c);
1445                        }
1446
1447                        TokenOrValue::Token(CssToken::Ident(ident))
1448                            if ident.as_ref().eq_ignore_ascii_case("inset") =>
1449                        {
1450                            if inset {
1451                                return None;
1452                            }
1453                            inset = true;
1454                        }
1455
1456                        other => {
1457                            if let Some(length) = parse_shadow_length(other) {
1458                                lengths.push(length);
1459                            } else {
1460                                return None;
1461                            }
1462                        }
1463                    }
1464                }
1465
1466                if !(2..=4).contains(&lengths.len()) {
1467                    return None;
1468                }
1469
1470                let x_offset = lengths[0].clone();
1471                let y_offset = lengths[1].clone();
1472                let blur_radius = lengths.get(2).cloned();
1473                let spread_radius = lengths.get(3).cloned();
1474
1475                Some(Shadow::new(x_offset, y_offset, blur_radius, spread_radius, color, inset))
1476            }
1477
1478            let mut parts = Vec::<&[TokenOrValue<'_>]>::new();
1479            let mut start = 0usize;
1480            for (idx, token) in tokens.iter().enumerate() {
1481                if matches!(token, TokenOrValue::Token(CssToken::Comma)) {
1482                    parts.push(&tokens[start..idx]);
1483                    start = idx + 1;
1484                }
1485            }
1486            parts.push(&tokens[start..]);
1487
1488            let mut parsed = Vec::new();
1489            for part in parts {
1490                let shadow = parse_single_shadow(part)?;
1491                parsed.push(shadow);
1492            }
1493
1494            Some(parsed)
1495        }
1496
1497        fn shadow_fallback(var: &Variable<'_>) -> Option<Vec<Shadow>> {
1498            var.fallback.as_ref().and_then(|TokenList(tokens)| parse_shadow_list(tokens))
1499        }
1500
1501        match property.clone() {
1502            // Display
1503            Property::Display(display) => {
1504                self.display.insert_rule(rule_id, display);
1505            }
1506
1507            // Visibility
1508            Property::Visibility(visibility) => {
1509                self.visibility.insert_rule(rule_id, visibility);
1510            }
1511
1512            // Opacity
1513            Property::Opacity(opacity) => {
1514                self.opacity.insert_rule(rule_id, opacity);
1515            }
1516
1517            // Clipping
1518            Property::ClipPath(clip) => {
1519                self.clip_path.insert_rule(rule_id, clip);
1520            }
1521
1522            // Filters
1523            Property::Filter(filter) => {
1524                self.filter.insert_rule(rule_id, filter);
1525            }
1526
1527            Property::BackdropFilter(filter) => {
1528                self.backdrop_filter.insert_rule(rule_id, filter);
1529            }
1530
1531            // Blend Mode
1532            Property::BlendMode(blend_mode) => {
1533                self.blend_mode.insert_rule(rule_id, blend_mode);
1534            }
1535
1536            // Layout Type
1537            Property::LayoutType(layout_type) => {
1538                self.layout_type.insert_rule(rule_id, layout_type);
1539            }
1540
1541            // Position Type
1542            Property::PositionType(position) => {
1543                self.position_type.insert_rule(rule_id, position);
1544            }
1545
1546            Property::Alignment(alignment) => {
1547                self.alignment.insert_rule(rule_id, alignment);
1548            }
1549
1550            Property::Direction(direction) => {
1551                self.direction.insert_rule(rule_id, direction);
1552            }
1553
1554            Property::Wrap(value) => {
1555                self.wrap.insert_rule(rule_id, value);
1556            }
1557            Property::GridColumns(columns) => {
1558                self.grid_columns.insert_rule(rule_id, columns);
1559            }
1560
1561            Property::GridRows(rows) => {
1562                self.grid_rows.insert_rule(rule_id, rows);
1563            }
1564
1565            Property::ColumnStart(start) => {
1566                self.column_start.insert_rule(rule_id, start);
1567            }
1568
1569            Property::ColumnSpan(span) => {
1570                self.column_span.insert_rule(rule_id, span);
1571            }
1572
1573            Property::RowStart(start) => {
1574                self.row_start.insert_rule(rule_id, start);
1575            }
1576
1577            Property::RowSpan(span) => {
1578                self.row_span.insert_rule(rule_id, span);
1579            }
1580
1581            // Space
1582            Property::Space(space) => {
1583                self.left.insert_rule(rule_id, space);
1584                self.right.insert_rule(rule_id, space);
1585                self.top.insert_rule(rule_id, space);
1586                self.bottom.insert_rule(rule_id, space);
1587            }
1588
1589            Property::Left(left) => {
1590                self.left.insert_rule(rule_id, left);
1591            }
1592
1593            Property::Right(right) => {
1594                self.right.insert_rule(rule_id, right);
1595            }
1596
1597            Property::Top(top) => {
1598                self.top.insert_rule(rule_id, top);
1599            }
1600
1601            Property::Bottom(bottom) => {
1602                self.bottom.insert_rule(rule_id, bottom);
1603            }
1604
1605            // Size
1606            Property::Size(size) => {
1607                self.width.insert_rule(rule_id, size);
1608                self.height.insert_rule(rule_id, size);
1609            }
1610
1611            Property::Width(width) => {
1612                self.width.insert_rule(rule_id, width);
1613            }
1614
1615            Property::Height(height) => {
1616                self.height.insert_rule(rule_id, height);
1617            }
1618
1619            // Padding
1620            Property::Padding(padding) => {
1621                self.padding_left.insert_rule(rule_id, padding);
1622                self.padding_right.insert_rule(rule_id, padding);
1623                self.padding_top.insert_rule(rule_id, padding);
1624                self.padding_bottom.insert_rule(rule_id, padding);
1625            }
1626
1627            Property::PaddingLeft(padding_left) => {
1628                self.padding_left.insert_rule(rule_id, padding_left);
1629            }
1630
1631            Property::PaddingRight(padding_right) => {
1632                self.padding_right.insert_rule(rule_id, padding_right);
1633            }
1634
1635            Property::PaddingTop(padding_top) => {
1636                self.padding_top.insert_rule(rule_id, padding_top);
1637            }
1638
1639            Property::PaddingBottom(padding_bottom) => {
1640                self.padding_bottom.insert_rule(rule_id, padding_bottom);
1641            }
1642
1643            Property::VerticalGap(vertical_gap) => {
1644                self.vertical_gap.insert_rule(rule_id, vertical_gap);
1645            }
1646
1647            Property::HorizontalGap(horizontal_gap) => {
1648                self.horizontal_gap.insert_rule(rule_id, horizontal_gap);
1649            }
1650
1651            Property::Gap(gap) => {
1652                self.horizontal_gap.insert_rule(rule_id, gap);
1653                self.vertical_gap.insert_rule(rule_id, gap);
1654            }
1655
1656            // Size Constraints
1657            Property::MinSize(min_size) => {
1658                self.min_width.insert_rule(rule_id, min_size);
1659                self.min_height.insert_rule(rule_id, min_size);
1660            }
1661
1662            Property::MinWidth(min_width) => {
1663                self.min_width.insert_rule(rule_id, min_width);
1664            }
1665
1666            Property::MinHeight(min_height) => {
1667                self.min_height.insert_rule(rule_id, min_height);
1668            }
1669
1670            Property::MaxSize(max_size) => {
1671                self.max_width.insert_rule(rule_id, max_size);
1672                self.max_height.insert_rule(rule_id, max_size);
1673            }
1674
1675            Property::MaxWidth(max_width) => {
1676                self.max_width.insert_rule(rule_id, max_width);
1677            }
1678
1679            Property::MaxHeight(max_height) => {
1680                self.max_height.insert_rule(rule_id, max_height);
1681            }
1682
1683            // Gap Constraints
1684            Property::MinGap(min_gap) => {
1685                self.min_horizontal_gap.insert_rule(rule_id, min_gap);
1686                self.min_vertical_gap.insert_rule(rule_id, min_gap);
1687            }
1688
1689            Property::MinHorizontalGap(min_gap) => {
1690                self.min_horizontal_gap.insert_rule(rule_id, min_gap);
1691            }
1692
1693            Property::MinVerticalGap(min_gap) => {
1694                self.min_vertical_gap.insert_rule(rule_id, min_gap);
1695            }
1696
1697            Property::MaxGap(max_gap) => {
1698                self.max_horizontal_gap.insert_rule(rule_id, max_gap);
1699                self.max_vertical_gap.insert_rule(rule_id, max_gap);
1700            }
1701
1702            Property::MaxHorizontalGap(max_gap) => {
1703                self.max_horizontal_gap.insert_rule(rule_id, max_gap);
1704            }
1705
1706            Property::MaxVerticalGap(max_gap) => {
1707                self.max_vertical_gap.insert_rule(rule_id, max_gap);
1708            }
1709
1710            // Background Colour
1711            Property::BackgroundColor(color) => {
1712                self.background_color.insert_rule(rule_id, color);
1713            }
1714
1715            // Border
1716            Property::Border(border) => {
1717                if let Some(border_color) = border.color {
1718                    self.border_color.insert_rule(rule_id, border_color);
1719                }
1720
1721                if let Some(border_width) = border.width {
1722                    self.border_width.insert_rule(rule_id, border_width.into());
1723                }
1724
1725                if let Some(border_style) = border.style {
1726                    self.border_style.insert_rule(rule_id, border_style.top);
1727                }
1728            }
1729
1730            // Border
1731            Property::BorderWidth(border_width) => {
1732                self.border_width.insert_rule(rule_id, border_width.top.0);
1733            }
1734
1735            Property::BorderColor(color) => {
1736                self.border_color.insert_rule(rule_id, color);
1737            }
1738
1739            Property::BorderStyle(style) => {
1740                self.border_style.insert_rule(rule_id, style.top);
1741            }
1742
1743            // Border Radius
1744            Property::CornerRadius(corner_radius) => {
1745                self.corner_bottom_left_radius.insert_rule(rule_id, corner_radius.bottom_left);
1746                self.corner_bottom_right_radius.insert_rule(rule_id, corner_radius.bottom_right);
1747                self.corner_top_left_radius.insert_rule(rule_id, corner_radius.top_left);
1748                self.corner_top_right_radius.insert_rule(rule_id, corner_radius.top_right);
1749            }
1750
1751            Property::CornerBottomLeftRadius(corner_radius) => {
1752                self.corner_bottom_left_radius.insert_rule(rule_id, corner_radius);
1753            }
1754
1755            Property::CornerTopLeftRadius(corner_radius) => {
1756                self.corner_top_left_radius.insert_rule(rule_id, corner_radius);
1757            }
1758
1759            Property::CornerBottomRightRadius(corner_radius) => {
1760                self.corner_bottom_right_radius.insert_rule(rule_id, corner_radius);
1761            }
1762
1763            Property::CornerTopRightRadius(corner_radius) => {
1764                self.corner_top_right_radius.insert_rule(rule_id, corner_radius);
1765            }
1766
1767            // Corner Shape
1768            Property::CornerShape(corner_shape) => {
1769                self.corner_top_left_shape.insert_rule(rule_id, corner_shape.0);
1770                self.corner_top_right_shape.insert_rule(rule_id, corner_shape.1);
1771                self.corner_bottom_right_shape.insert_rule(rule_id, corner_shape.2);
1772                self.corner_bottom_left_shape.insert_rule(rule_id, corner_shape.3);
1773            }
1774
1775            Property::CornerTopLeftShape(corner_shape) => {
1776                self.corner_top_left_shape.insert_rule(rule_id, corner_shape);
1777            }
1778
1779            Property::CornerTopRightShape(corner_shape) => {
1780                self.corner_top_right_shape.insert_rule(rule_id, corner_shape);
1781            }
1782
1783            Property::CornerBottomLeftShape(corner_shape) => {
1784                self.corner_bottom_left_shape.insert_rule(rule_id, corner_shape);
1785            }
1786
1787            Property::CornerBottomRightShape(corner_shape) => {
1788                self.corner_bottom_right_shape.insert_rule(rule_id, corner_shape);
1789            }
1790
1791            // Font Family
1792            Property::FontFamily(font_family) => {
1793                self.font_family.insert_rule(
1794                    rule_id,
1795                    font_family
1796                        .iter()
1797                        .map(|family| match family {
1798                            FontFamily::Named(name) => FamilyOwned::Named(name.to_string()),
1799                            FontFamily::Generic(generic) => FamilyOwned::Generic(*generic),
1800                        })
1801                        .collect::<Vec<_>>(),
1802                );
1803            }
1804
1805            // Font Color
1806            Property::FontColor(font_color) => {
1807                self.font_color.insert_rule(rule_id, font_color);
1808            }
1809
1810            // Font Size
1811            Property::FontSize(font_size) => {
1812                self.font_size.insert_rule(rule_id, font_size);
1813            }
1814
1815            // Font Weight
1816            Property::FontWeight(font_weight) => {
1817                self.font_weight.insert_rule(rule_id, font_weight);
1818            }
1819
1820            // Font Slant
1821            Property::FontSlant(font_slant) => {
1822                self.font_slant.insert_rule(rule_id, font_slant);
1823            }
1824
1825            // Font Width
1826            Property::FontWidth(font_width) => {
1827                self.font_width.insert_rule(rule_id, font_width);
1828            }
1829
1830            // Font Variation Settings
1831            Property::FontVariationSettings(font_variation_settings) => {
1832                self.font_variation_settings.insert_rule(rule_id, font_variation_settings);
1833            }
1834
1835            // Caret Color
1836            Property::CaretColor(caret_color) => {
1837                self.caret_color.insert_rule(rule_id, caret_color);
1838            }
1839
1840            // Selection Color
1841            Property::SelectionColor(selection_color) => {
1842                self.selection_color.insert_rule(rule_id, selection_color);
1843            }
1844
1845            // Transform
1846            Property::Transform(transforms) => {
1847                self.transform.insert_rule(rule_id, transforms);
1848            }
1849
1850            Property::TransformOrigin(transform_origin) => {
1851                let x = transform_origin.x.to_length_or_percentage();
1852                let y = transform_origin.y.to_length_or_percentage();
1853                self.transform_origin.insert_rule(rule_id, Translate { x, y });
1854            }
1855
1856            Property::Translate(translate) => {
1857                self.translate.insert_rule(rule_id, translate);
1858            }
1859
1860            Property::Rotate(rotate) => {
1861                self.rotate.insert_rule(rule_id, rotate);
1862            }
1863
1864            Property::Scale(scale) => {
1865                self.scale.insert_rule(rule_id, scale);
1866            }
1867
1868            // Overflow
1869            Property::Overflow(overflow) => {
1870                self.overflowx.insert_rule(rule_id, overflow);
1871                self.overflowy.insert_rule(rule_id, overflow);
1872            }
1873
1874            Property::OverflowX(overflow) => {
1875                self.overflowx.insert_rule(rule_id, overflow);
1876            }
1877
1878            Property::OverflowY(overflow) => {
1879                self.overflowy.insert_rule(rule_id, overflow);
1880            }
1881
1882            // Z Index
1883            Property::ZIndex(z_index) => self.z_index.insert_rule(rule_id, z_index),
1884
1885            // Outline
1886            Property::Outline(outline) => {
1887                if let Some(outline_color) = outline.color {
1888                    self.outline_color.insert_rule(rule_id, outline_color);
1889                }
1890
1891                if let Some(outline_width) = outline.width {
1892                    self.outline_width.insert_rule(rule_id, outline_width.into());
1893                }
1894            }
1895
1896            Property::OutlineColor(outline_color) => {
1897                self.outline_color.insert_rule(rule_id, outline_color);
1898            }
1899
1900            Property::OutlineWidth(outline_width) => {
1901                self.outline_width.insert_rule(rule_id, outline_width.left.0);
1902            }
1903
1904            Property::OutlineOffset(outline_offset) => {
1905                self.outline_offset.insert_rule(rule_id, outline_offset);
1906            }
1907
1908            // Background Images & Gradients
1909            Property::BackgroundImage(images) => {
1910                let images = images
1911                    .into_iter()
1912                    .filter_map(|img| match img {
1913                        BackgroundImage::None => None,
1914                        BackgroundImage::Gradient(gradient) => {
1915                            Some(ImageOrGradient::Gradient(*gradient))
1916                        }
1917                        BackgroundImage::Url(url) => {
1918                            Some(ImageOrGradient::Image(url.url.to_string()))
1919                        }
1920                    })
1921                    .collect::<Vec<_>>();
1922
1923                self.background_image.insert_rule(rule_id, images);
1924            }
1925
1926            // Background Size
1927            Property::BackgroundSize(sizes) => {
1928                self.background_size.insert_rule(rule_id, sizes);
1929            }
1930
1931            // Text Wrapping
1932            Property::TextWrap(text_wrap) => {
1933                self.text_wrap.insert_rule(rule_id, text_wrap);
1934            }
1935
1936            // Text Alignment
1937            Property::TextAlign(text_align) => {
1938                self.text_align.insert_rule(rule_id, text_align);
1939            }
1940
1941            // Box Shadows
1942            Property::Shadow(shadows) => {
1943                self.shadow.insert_rule(rule_id, shadows);
1944            }
1945
1946            // Cursor Icon
1947            Property::Cursor(cursor) => {
1948                self.cursor.insert_rule(rule_id, cursor);
1949            }
1950
1951            Property::PointerEvents(pointer_events) => {
1952                self.pointer_events.insert_rule(rule_id, pointer_events);
1953            }
1954
1955            Property::TextOverflow(text_overflow) => {
1956                self.text_overflow.insert_rule(rule_id, text_overflow);
1957            }
1958            Property::LineClamp(line_clamp) => {
1959                self.line_clamp.insert_rule(rule_id, line_clamp);
1960            }
1961            Property::TextDecorationLine(line) => {
1962                self.text_decoration_line.insert_rule(rule_id, line);
1963            }
1964            Property::TextStroke(stroke) => {
1965                self.text_stroke_width.insert_rule(rule_id, stroke.width);
1966                self.text_stroke_style.insert_rule(rule_id, stroke.style);
1967            }
1968            Property::TextStrokeWidth(stroke_width) => {
1969                self.text_stroke_width.insert_rule(rule_id, stroke_width);
1970            }
1971            Property::TextStrokeStyle(stroke_style) => {
1972                self.text_stroke_style.insert_rule(rule_id, stroke_style);
1973            }
1974            Property::Fill(fill) => {
1975                self.fill.insert_rule(rule_id, fill);
1976            }
1977
1978            // Unparsed. TODO: Log the error.
1979            Property::Unparsed(unparsed) => {
1980                macro_rules! parse_color_var {
1981                    ($prop:expr) => {
1982                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
1983                            $prop.insert_variable_rule(
1984                                rule_id,
1985                                variable_hash(var),
1986                                color_fallback(var),
1987                            );
1988                        }
1989                    };
1990                }
1991                macro_rules! parse_length_var {
1992                    ($($prop:expr),+) => {
1993                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
1994                            let hash = variable_hash(var);
1995                            let fallback = length_fallback(var);
1996                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
1997                        }
1998                    };
1999                }
2000                macro_rules! parse_font_size_var {
2001                    ($prop:expr) => {
2002                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2003                            $prop.insert_variable_rule(
2004                                rule_id,
2005                                variable_hash(var),
2006                                font_size_fallback(var),
2007                            );
2008                        }
2009                    };
2010                }
2011                macro_rules! parse_units_var {
2012                    ($($prop:expr),+) => {
2013                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2014                            let hash = variable_hash(var);
2015                            let fallback = units_fallback(var);
2016                            $($prop.insert_variable_rule(rule_id, hash, fallback.clone());)+
2017                        }
2018                    };
2019                }
2020                match unparsed.name.as_ref() {
2021                    "background-color" => parse_color_var!(self.background_color),
2022                    "border-color" => parse_color_var!(self.border_color),
2023                    "outline-color" => parse_color_var!(self.outline_color),
2024                    "color" => parse_color_var!(self.font_color),
2025                    "caret-color" => parse_color_var!(self.caret_color),
2026                    "selection-color" => parse_color_var!(self.selection_color),
2027                    "fill" => parse_color_var!(self.fill),
2028                    "underline-color" => parse_color_var!(self.underline_color),
2029                    "overline-color" => parse_color_var!(self.overline_color),
2030                    "strikethrough-color" => parse_color_var!(self.strikethrough_color),
2031                    "font-size" => parse_font_size_var!(self.font_size),
2032                    "corner-radius" => parse_length_var!(
2033                        self.corner_top_left_radius,
2034                        self.corner_top_right_radius,
2035                        self.corner_bottom_left_radius,
2036                        self.corner_bottom_right_radius
2037                    ),
2038                    "corner-top-left-radius" => parse_length_var!(self.corner_top_left_radius),
2039                    "corner-top-right-radius" => parse_length_var!(self.corner_top_right_radius),
2040                    "corner-bottom-left-radius" => {
2041                        parse_length_var!(self.corner_bottom_left_radius)
2042                    }
2043                    "corner-bottom-right-radius" => {
2044                        parse_length_var!(self.corner_bottom_right_radius)
2045                    }
2046                    "border-width" => parse_length_var!(self.border_width),
2047                    "border" => {
2048                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2049                            let hash = variable_hash(var);
2050                            self.border_width.insert_variable_rule(
2051                                rule_id,
2052                                hash,
2053                                length_fallback(var),
2054                            );
2055                            self.border_color.insert_variable_rule(
2056                                rule_id,
2057                                hash,
2058                                color_fallback(var),
2059                            );
2060                        }
2061                    }
2062                    "outline" => {
2063                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2064                            let hash = variable_hash(var);
2065                            self.outline_width.insert_variable_rule(
2066                                rule_id,
2067                                hash,
2068                                length_fallback(var),
2069                            );
2070                            self.outline_color.insert_variable_rule(
2071                                rule_id,
2072                                hash,
2073                                color_fallback(var),
2074                            );
2075                        }
2076                    }
2077                    "outline-width" => parse_length_var!(self.outline_width),
2078                    "outline-offset" => parse_length_var!(self.outline_offset),
2079                    "left" => parse_units_var!(self.left),
2080                    "right" => parse_units_var!(self.right),
2081                    "top" => parse_units_var!(self.top),
2082                    "bottom" => parse_units_var!(self.bottom),
2083                    "space" => parse_units_var!(self.left, self.right, self.top, self.bottom),
2084                    "width" => parse_units_var!(self.width),
2085                    "height" => parse_units_var!(self.height),
2086                    "size" => parse_units_var!(self.width, self.height),
2087                    "min-width" => parse_units_var!(self.min_width),
2088                    "max-width" => parse_units_var!(self.max_width),
2089                    "min-height" => parse_units_var!(self.min_height),
2090                    "max-height" => parse_units_var!(self.max_height),
2091                    "min-size" => parse_units_var!(self.min_width, self.min_height),
2092                    "max-size" => parse_units_var!(self.max_width, self.max_height),
2093                    "padding-left" => parse_units_var!(self.padding_left),
2094                    "padding-right" => parse_units_var!(self.padding_right),
2095                    "padding-top" => parse_units_var!(self.padding_top),
2096                    "padding-bottom" => parse_units_var!(self.padding_bottom),
2097                    "padding" => parse_units_var!(
2098                        self.padding_left,
2099                        self.padding_right,
2100                        self.padding_top,
2101                        self.padding_bottom
2102                    ),
2103                    "row-gap" | "vertical-gap" => parse_units_var!(self.vertical_gap),
2104                    "column-gap" | "horizontal-gap" => parse_units_var!(self.horizontal_gap),
2105                    "gap" => parse_units_var!(self.vertical_gap, self.horizontal_gap),
2106                    "min-gap" => {
2107                        parse_units_var!(self.min_horizontal_gap, self.min_vertical_gap)
2108                    }
2109                    "max-gap" => {
2110                        parse_units_var!(self.max_horizontal_gap, self.max_vertical_gap)
2111                    }
2112                    "opacity" => {
2113                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2114                            self.opacity.insert_variable_rule(
2115                                rule_id,
2116                                variable_hash(var),
2117                                opacity_fallback(var),
2118                            );
2119                        }
2120                    }
2121                    "shadow" => {
2122                        if let Some(TokenOrValue::Var(var)) = unparsed.value.0.first() {
2123                            self.shadow.insert_variable_rule(
2124                                rule_id,
2125                                variable_hash(var),
2126                                shadow_fallback(var),
2127                            );
2128                        }
2129                    }
2130                    n => warn!("Unparsed {} {:?}", n, unparsed.value),
2131                }
2132            }
2133
2134            Property::Custom(custom) => {
2135                let mut s = DefaultHasher::new();
2136                custom.name.hash(&mut s);
2137                let variable_name_hash = s.finish();
2138
2139                if let Some(shadows) = parse_shadow_list(&custom.value.0) {
2140                    if let Some(store) = self.custom_shadow_props.get_mut(&variable_name_hash) {
2141                        store.insert_rule(rule_id, shadows);
2142                    } else {
2143                        let mut store = AnimatableVarSet::default();
2144                        store.insert_rule(rule_id, shadows);
2145                        self.custom_shadow_props.insert(variable_name_hash, store);
2146                    }
2147                }
2148
2149                // Parse custom properties and store them
2150                for token in custom.value.0.iter() {
2151                    // Try parsing colors
2152                    if let TokenOrValue::Color(color) = token {
2153                        if let Some(store) = self.custom_color_props.get_mut(&variable_name_hash) {
2154                            store.insert_rule(rule_id, *color);
2155                        } else {
2156                            let mut store = AnimatableVarSet::default();
2157                            store.insert_rule(rule_id, *color);
2158                            self.custom_color_props.insert(variable_name_hash, store);
2159                        }
2160                    }
2161
2162                    // Parse length/percentage tokens into custom_length_props
2163                    match token {
2164                        TokenOrValue::Token(CssToken::Dimension { value, unit, .. }) => {
2165                            let lop = if unit.as_ref().eq_ignore_ascii_case("px") {
2166                                Some(LengthOrPercentage::Length(Length::Value(LengthValue::Px(
2167                                    *value,
2168                                ))))
2169                            } else {
2170                                None
2171                            };
2172                            if let Some(lop) = lop {
2173                                if let Some(store) =
2174                                    self.custom_length_props.get_mut(&variable_name_hash)
2175                                {
2176                                    store.insert_rule(rule_id, lop.clone());
2177                                } else {
2178                                    let mut store = AnimatableVarSet::default();
2179                                    store.insert_rule(rule_id, lop.clone());
2180                                    self.custom_length_props.insert(variable_name_hash, store);
2181                                }
2182                                // Also try storing as FontSize
2183                                let fs = FontSize(Length::Value(LengthValue::Px(*value)));
2184                                if let Some(store) =
2185                                    self.custom_font_size_props.get_mut(&variable_name_hash)
2186                                {
2187                                    store.insert_rule(rule_id, fs);
2188                                } else {
2189                                    let mut store = AnimatableVarSet::default();
2190                                    store.insert_rule(rule_id, fs);
2191                                    self.custom_font_size_props.insert(variable_name_hash, store);
2192                                }
2193                                // Also store as Units::Pixels
2194                                let units_val = Units::Pixels(*value);
2195                                if let Some(store) =
2196                                    self.custom_units_props.get_mut(&variable_name_hash)
2197                                {
2198                                    store.insert_rule(rule_id, units_val);
2199                                } else {
2200                                    let mut store = AnimatableVarSet::default();
2201                                    store.insert_rule(rule_id, units_val);
2202                                    self.custom_units_props.insert(variable_name_hash, store);
2203                                }
2204                            } else if unit.as_ref().eq_ignore_ascii_case("s") {
2205                                // "1s" => Units::Stretch(1.0)
2206                                let units_val = Units::Stretch(*value);
2207                                if let Some(store) =
2208                                    self.custom_units_props.get_mut(&variable_name_hash)
2209                                {
2210                                    store.insert_rule(rule_id, units_val);
2211                                } else {
2212                                    let mut store = AnimatableVarSet::default();
2213                                    store.insert_rule(rule_id, units_val);
2214                                    self.custom_units_props.insert(variable_name_hash, store);
2215                                }
2216                            }
2217                        }
2218                        TokenOrValue::Token(CssToken::Ident(ident))
2219                            if ident.as_ref().eq_ignore_ascii_case("auto") =>
2220                        {
2221                            let units_val = Units::Auto;
2222                            if let Some(store) =
2223                                self.custom_units_props.get_mut(&variable_name_hash)
2224                            {
2225                                store.insert_rule(rule_id, units_val);
2226                            } else {
2227                                let mut store = AnimatableVarSet::default();
2228                                store.insert_rule(rule_id, units_val);
2229                                self.custom_units_props.insert(variable_name_hash, store);
2230                            }
2231                        }
2232                        TokenOrValue::Token(CssToken::Percentage { unit_value, .. }) => {
2233                            let lop = LengthOrPercentage::Percentage(*unit_value * 100.0);
2234                            if let Some(store) =
2235                                self.custom_length_props.get_mut(&variable_name_hash)
2236                            {
2237                                store.insert_rule(rule_id, lop);
2238                            } else {
2239                                let mut store = AnimatableVarSet::default();
2240                                store.insert_rule(rule_id, lop);
2241                                self.custom_length_props.insert(variable_name_hash, store);
2242                            }
2243                            // Also store as Units::Percentage
2244                            let units_val = Units::Percentage(*unit_value * 100.0);
2245                            if let Some(store) =
2246                                self.custom_units_props.get_mut(&variable_name_hash)
2247                            {
2248                                store.insert_rule(rule_id, units_val);
2249                            } else {
2250                                let mut store = AnimatableVarSet::default();
2251                                store.insert_rule(rule_id, units_val);
2252                                self.custom_units_props.insert(variable_name_hash, store);
2253                            }
2254                            // Also store as Opacity (percentage as 0..1)
2255                            let opacity_val = Opacity(*unit_value);
2256                            if let Some(store) =
2257                                self.custom_opacity_props.get_mut(&variable_name_hash)
2258                            {
2259                                store.insert_rule(rule_id, opacity_val);
2260                            } else {
2261                                let mut store = AnimatableVarSet::default();
2262                                store.insert_rule(rule_id, opacity_val);
2263                                self.custom_opacity_props.insert(variable_name_hash, store);
2264                            }
2265                        }
2266                        TokenOrValue::Var(var) => {
2267                            let name_hash = variable_hash(var);
2268                            // Store var reference in all maps (type is unknown at parse time)
2269                            if let Some(store) =
2270                                self.custom_color_props.get_mut(&variable_name_hash)
2271                            {
2272                                store.insert_variable_rule(rule_id, name_hash, color_fallback(var));
2273                            } else {
2274                                let mut store = AnimatableVarSet::default();
2275                                store.insert_variable_rule(rule_id, name_hash, color_fallback(var));
2276                                self.custom_color_props.insert(variable_name_hash, store);
2277                            }
2278                            if let Some(store) =
2279                                self.custom_length_props.get_mut(&variable_name_hash)
2280                            {
2281                                store.insert_variable_rule(
2282                                    rule_id,
2283                                    name_hash,
2284                                    length_fallback(var),
2285                                );
2286                            } else {
2287                                let mut store: AnimatableVarSet<LengthOrPercentage> =
2288                                    AnimatableVarSet::default();
2289                                store.insert_variable_rule(
2290                                    rule_id,
2291                                    name_hash,
2292                                    length_fallback(var),
2293                                );
2294                                self.custom_length_props.insert(variable_name_hash, store);
2295                            }
2296                            if let Some(store) =
2297                                self.custom_font_size_props.get_mut(&variable_name_hash)
2298                            {
2299                                store.insert_variable_rule(
2300                                    rule_id,
2301                                    name_hash,
2302                                    font_size_fallback(var),
2303                                );
2304                            } else {
2305                                let mut store: AnimatableVarSet<FontSize> =
2306                                    AnimatableVarSet::default();
2307                                store.insert_variable_rule(
2308                                    rule_id,
2309                                    name_hash,
2310                                    font_size_fallback(var),
2311                                );
2312                                self.custom_font_size_props.insert(variable_name_hash, store);
2313                            }
2314                            if let Some(store) =
2315                                self.custom_units_props.get_mut(&variable_name_hash)
2316                            {
2317                                store.insert_variable_rule(rule_id, name_hash, units_fallback(var));
2318                            } else {
2319                                let mut store: AnimatableVarSet<Units> =
2320                                    AnimatableVarSet::default();
2321                                store.insert_variable_rule(rule_id, name_hash, units_fallback(var));
2322                                self.custom_units_props.insert(variable_name_hash, store);
2323                            }
2324                            if let Some(store) =
2325                                self.custom_opacity_props.get_mut(&variable_name_hash)
2326                            {
2327                                store.insert_variable_rule(
2328                                    rule_id,
2329                                    name_hash,
2330                                    opacity_fallback(var),
2331                                );
2332                            } else {
2333                                let mut store: AnimatableVarSet<Opacity> =
2334                                    AnimatableVarSet::default();
2335                                store.insert_variable_rule(
2336                                    rule_id,
2337                                    name_hash,
2338                                    opacity_fallback(var),
2339                                );
2340                                self.custom_opacity_props.insert(variable_name_hash, store);
2341                            }
2342
2343                            if let Some(store) =
2344                                self.custom_shadow_props.get_mut(&variable_name_hash)
2345                            {
2346                                store.insert_variable_rule(
2347                                    rule_id,
2348                                    name_hash,
2349                                    shadow_fallback(var),
2350                                );
2351                            } else {
2352                                let mut store: AnimatableVarSet<Vec<Shadow>> =
2353                                    AnimatableVarSet::default();
2354                                store.insert_variable_rule(
2355                                    rule_id,
2356                                    name_hash,
2357                                    shadow_fallback(var),
2358                                );
2359                                self.custom_shadow_props.insert(variable_name_hash, store);
2360                            }
2361                        }
2362                        TokenOrValue::Token(CssToken::Number { value, .. }) => {
2363                            // Plain number like 0.5 → Opacity
2364                            let opacity_val = Opacity(*value);
2365                            if let Some(store) =
2366                                self.custom_opacity_props.get_mut(&variable_name_hash)
2367                            {
2368                                store.insert_rule(rule_id, opacity_val);
2369                            } else {
2370                                let mut store = AnimatableVarSet::default();
2371                                store.insert_rule(rule_id, opacity_val);
2372                                self.custom_opacity_props.insert(variable_name_hash, store);
2373                            }
2374                        }
2375                        _ => {}
2376                    }
2377                }
2378            }
2379            _ => {}
2380        }
2381    }
2382
2383    // Helper function for generating AnimationState from a transition definition.
2384    fn add_transition<T: Default + Interpolator>(
2385        &self,
2386        transition: &Transition,
2387    ) -> AnimationState<T> {
2388        let timing_function = transition
2389            .timing_function
2390            .map(|easing| match easing {
2391                EasingFunction::Linear => TimingFunction::linear(),
2392                EasingFunction::Ease => TimingFunction::ease(),
2393                EasingFunction::EaseIn => TimingFunction::ease_in(),
2394                EasingFunction::EaseOut => TimingFunction::ease_out(),
2395                EasingFunction::EaseInOut => TimingFunction::ease_in_out(),
2396                EasingFunction::CubicBezier(x1, y1, x2, y2) => TimingFunction::new(x1, y1, x2, y2),
2397            })
2398            .unwrap_or_default();
2399
2400        AnimationState::new(Animation::null())
2401            .with_duration(transition.duration)
2402            .with_delay(transition.delay.unwrap_or_default())
2403            .with_keyframe(Keyframe { time: 0.0, value: Default::default(), timing_function })
2404            .with_keyframe(Keyframe { time: 1.0, value: Default::default(), timing_function })
2405    }
2406
2407    // Add style data for the given entity.
2408    pub(crate) fn add(&mut self, entity: Entity) {
2409        self.pseudo_classes.insert(entity, PseudoClassFlags::VALID);
2410        self.classes.insert(entity, HashSet::new());
2411        self.abilities.insert(entity, Abilities::default());
2412        self.system_flags = SystemFlags::RELAYOUT;
2413        self.restyle.insert(entity);
2414        self.reaccess.insert(entity);
2415        self.retransform.insert(entity);
2416        self.reclip.insert(entity);
2417    }
2418
2419    // Remove style data for the given entity.
2420    pub(crate) fn remove(&mut self, entity: Entity) {
2421        self.ids.remove(entity);
2422        self.classes.remove(entity);
2423        self.pseudo_classes.remove(entity);
2424        self.disabled.remove(entity);
2425        self.abilities.remove(entity);
2426
2427        self.name.remove(entity);
2428        self.role.remove(entity);
2429        // self.default_action_verb.remove(entity);
2430        self.live.remove(entity);
2431        self.labelled_by.remove(entity);
2432        self.described_by.remove(entity);
2433        self.controls.remove(entity);
2434        self.active_descendant.remove(entity);
2435        self.expanded.remove(entity);
2436        self.selected.remove(entity);
2437        self.hidden.remove(entity);
2438        self.orientation.remove(entity);
2439        self.text_value.remove(entity);
2440        self.numeric_value.remove(entity);
2441
2442        // Display
2443        self.display.remove(entity);
2444        // Visibility
2445        self.visibility.remove(entity);
2446        // Opacity
2447        self.opacity.remove(entity);
2448        // Z Order
2449        self.z_index.remove(entity);
2450        // Clipping
2451        self.clip_path.remove(entity);
2452
2453        self.overflowx.remove(entity);
2454        self.overflowy.remove(entity);
2455
2456        // Filters
2457        self.filter.remove(entity);
2458        self.backdrop_filter.remove(entity);
2459
2460        // Blend Mode
2461        self.blend_mode.remove(entity);
2462
2463        // Transform
2464        self.transform.remove(entity);
2465        self.transform_origin.remove(entity);
2466        self.translate.remove(entity);
2467        self.rotate.remove(entity);
2468        self.scale.remove(entity);
2469
2470        // Border
2471        self.border_width.remove(entity);
2472        self.border_color.remove(entity);
2473        self.border_style.remove(entity);
2474
2475        // Corner Shape
2476        self.corner_bottom_left_shape.remove(entity);
2477        self.corner_bottom_right_shape.remove(entity);
2478        self.corner_top_left_shape.remove(entity);
2479        self.corner_top_right_shape.remove(entity);
2480
2481        // Corner Radius
2482        self.corner_bottom_left_radius.remove(entity);
2483        self.corner_bottom_right_radius.remove(entity);
2484        self.corner_top_left_radius.remove(entity);
2485        self.corner_top_right_radius.remove(entity);
2486
2487        // Corner Smoothing
2488        self.corner_bottom_left_smoothing.remove(entity);
2489        self.corner_bottom_right_smoothing.remove(entity);
2490        self.corner_top_left_smoothing.remove(entity);
2491        self.corner_top_right_smoothing.remove(entity);
2492
2493        // Outline
2494        self.outline_width.remove(entity);
2495        self.outline_color.remove(entity);
2496        self.outline_offset.remove(entity);
2497
2498        // Background
2499        self.background_color.remove(entity);
2500        self.background_image.remove(entity);
2501        self.background_size.remove(entity);
2502
2503        // Box Shadow
2504        self.shadow.remove(entity);
2505
2506        // Text and Font
2507        self.text.remove(entity);
2508        self.text_wrap.remove(entity);
2509        self.text_overflow.remove(entity);
2510        self.line_clamp.remove(entity);
2511        self.text_align.remove(entity);
2512        self.font_family.remove(entity);
2513        self.font_color.remove(entity);
2514        self.font_size.remove(entity);
2515        self.font_weight.remove(entity);
2516        self.font_slant.remove(entity);
2517        self.font_width.remove(entity);
2518        self.font_variation_settings.remove(entity);
2519        self.caret_color.remove(entity);
2520        self.selection_color.remove(entity);
2521        self.text_decoration_line.remove(entity);
2522        self.text_stroke_width.remove(entity);
2523        self.text_stroke_style.remove(entity);
2524
2525        // Cursor
2526        self.cursor.remove(entity);
2527
2528        self.pointer_events.remove(entity);
2529
2530        // Layout Type
2531        self.layout_type.remove(entity);
2532
2533        // Position Type
2534        self.position_type.remove(entity);
2535
2536        self.alignment.remove(entity);
2537        self.direction.remove(entity);
2538        self.wrap.remove(entity);
2539
2540        // Grid
2541        self.grid_columns.remove(entity);
2542        self.grid_rows.remove(entity);
2543        self.column_start.remove(entity);
2544        self.column_span.remove(entity);
2545        self.row_start.remove(entity);
2546        self.row_span.remove(entity);
2547
2548        // Space
2549        self.left.remove(entity);
2550        self.right.remove(entity);
2551        self.top.remove(entity);
2552        self.bottom.remove(entity);
2553
2554        // Padding
2555        self.padding_left.remove(entity);
2556        self.padding_right.remove(entity);
2557        self.padding_top.remove(entity);
2558        self.padding_bottom.remove(entity);
2559        self.vertical_gap.remove(entity);
2560        self.horizontal_gap.remove(entity);
2561
2562        // Scrolling
2563        self.vertical_scroll.remove(entity);
2564        self.horizontal_scroll.remove(entity);
2565
2566        // Size
2567        self.width.remove(entity);
2568        self.height.remove(entity);
2569
2570        // Size Constraints
2571        self.min_width.remove(entity);
2572        self.max_width.remove(entity);
2573        self.min_height.remove(entity);
2574        self.max_height.remove(entity);
2575
2576        self.min_horizontal_gap.remove(entity);
2577        self.max_horizontal_gap.remove(entity);
2578        self.min_vertical_gap.remove(entity);
2579        self.max_vertical_gap.remove(entity);
2580
2581        self.text_range.remove(entity);
2582        self.text_span.remove(entity);
2583
2584        self.fill.remove(entity);
2585
2586        // Remove per-entity data from custom property stores
2587        for store in self.custom_color_props.values_mut() {
2588            store.remove(entity);
2589        }
2590        for store in self.custom_length_props.values_mut() {
2591            store.remove(entity);
2592        }
2593        for store in self.custom_font_size_props.values_mut() {
2594            store.remove(entity);
2595        }
2596        for store in self.custom_units_props.values_mut() {
2597            store.remove(entity);
2598        }
2599        for store in self.custom_opacity_props.values_mut() {
2600            store.remove(entity);
2601        }
2602    }
2603
2604    pub(crate) fn needs_restyle(&mut self, entity: Entity) {
2605        if entity == Entity::null() || self.restyle.contains(&entity) {
2606            return;
2607        }
2608        self.restyle.insert(entity);
2609    }
2610
2611    pub(crate) fn needs_relayout(&mut self) {
2612        self.system_flags.set(SystemFlags::RELAYOUT, true);
2613    }
2614
2615    pub(crate) fn needs_access_update(&mut self, entity: Entity) {
2616        self.reaccess.insert(entity);
2617    }
2618
2619    pub(crate) fn needs_text_update(&mut self, entity: Entity) {
2620        self.text_construction.insert(entity);
2621        self.text_layout.insert(entity);
2622    }
2623
2624    pub(crate) fn needs_text_layout(&mut self, entity: Entity) {
2625        self.text_layout.insert(entity);
2626    }
2627
2628    pub(crate) fn needs_retransform(&mut self, entity: Entity) {
2629        self.retransform.insert(entity);
2630    }
2631
2632    pub(crate) fn needs_reclip(&mut self, entity: Entity) {
2633        self.reclip.insert(entity);
2634    }
2635
2636    // pub fn should_redraw<F: FnOnce()>(&mut self, f: F) {
2637    //     if !self.redraw_list.is_empty() {
2638    //         f();
2639    //     }
2640    // }
2641
2642    // Remove all shared style data.
2643    pub(crate) fn clear_style_rules(&mut self) {
2644        self.disabled.clear_rules();
2645        // Display
2646        self.display.clear_rules();
2647        // Visibility
2648        self.visibility.clear_rules();
2649        // Opacity
2650        self.opacity.clear_rules();
2651        // Z Order
2652        self.z_index.clear_rules();
2653
2654        // Clipping
2655        self.clip_path.clear_rules();
2656
2657        // Filters
2658        self.filter.clear_rules();
2659        self.backdrop_filter.clear_rules();
2660
2661        // Blend Mode
2662        self.blend_mode.clear_rules();
2663
2664        // Transform
2665        self.transform.clear_rules();
2666        self.transform_origin.clear_rules();
2667        self.translate.clear_rules();
2668        self.rotate.clear_rules();
2669        self.scale.clear_rules();
2670
2671        self.overflowx.clear_rules();
2672        self.overflowy.clear_rules();
2673
2674        // Border
2675        self.border_width.clear_rules();
2676        self.border_color.clear_rules();
2677        self.border_style.clear_rules();
2678
2679        // Corner Shape
2680        self.corner_bottom_left_shape.clear_rules();
2681        self.corner_bottom_right_shape.clear_rules();
2682        self.corner_top_left_shape.clear_rules();
2683        self.corner_top_right_shape.clear_rules();
2684
2685        // Corner Radius
2686        self.corner_bottom_left_radius.clear_rules();
2687        self.corner_bottom_right_radius.clear_rules();
2688        self.corner_top_left_radius.clear_rules();
2689        self.corner_top_right_radius.clear_rules();
2690
2691        // Corner Smoothing
2692        self.corner_bottom_left_smoothing.clear_rules();
2693        self.corner_bottom_right_smoothing.clear_rules();
2694        self.corner_top_left_smoothing.clear_rules();
2695        self.corner_top_right_smoothing.clear_rules();
2696
2697        // Outline
2698        self.outline_width.clear_rules();
2699        self.outline_color.clear_rules();
2700        self.outline_offset.clear_rules();
2701
2702        // Background
2703        self.background_color.clear_rules();
2704        self.background_image.clear_rules();
2705        self.background_size.clear_rules();
2706
2707        self.shadow.clear_rules();
2708
2709        self.layout_type.clear_rules();
2710        self.position_type.clear_rules();
2711        self.alignment.clear_rules();
2712        self.direction.clear_rules();
2713        self.wrap.clear_rules();
2714
2715        // Grid
2716        self.grid_columns.clear_rules();
2717        self.grid_rows.clear_rules();
2718        self.column_start.clear_rules();
2719        self.column_span.clear_rules();
2720
2721        // Space
2722        self.left.clear_rules();
2723        self.right.clear_rules();
2724        self.top.clear_rules();
2725        self.bottom.clear_rules();
2726
2727        // Size
2728        self.width.clear_rules();
2729        self.height.clear_rules();
2730
2731        // Size Constraints
2732        self.min_width.clear_rules();
2733        self.max_width.clear_rules();
2734        self.min_height.clear_rules();
2735        self.max_height.clear_rules();
2736
2737        self.min_horizontal_gap.clear_rules();
2738        self.max_horizontal_gap.clear_rules();
2739        self.min_vertical_gap.clear_rules();
2740        self.max_vertical_gap.clear_rules();
2741
2742        // Padding
2743        self.padding_left.clear_rules();
2744        self.padding_right.clear_rules();
2745        self.padding_top.clear_rules();
2746        self.padding_bottom.clear_rules();
2747        self.horizontal_gap.clear_rules();
2748        self.vertical_gap.clear_rules();
2749
2750        // Scrolling
2751        self.horizontal_scroll.clear_rules();
2752        self.vertical_scroll.clear_rules();
2753
2754        // Text and Font
2755        self.text_wrap.clear_rules();
2756        self.text_overflow.clear_rules();
2757        self.line_clamp.clear_rules();
2758        self.text_align.clear_rules();
2759        self.font_family.clear_rules();
2760        self.font_weight.clear_rules();
2761        self.font_slant.clear_rules();
2762        self.font_color.clear_rules();
2763        self.font_size.clear_rules();
2764        self.font_variation_settings.clear_rules();
2765        self.selection_color.clear_rules();
2766        self.caret_color.clear_rules();
2767        self.text_decoration_line.clear_rules();
2768        self.text_stroke_width.clear_rules();
2769        self.text_stroke_style.clear_rules();
2770
2771        self.cursor.clear_rules();
2772
2773        self.pointer_events.clear_rules();
2774
2775        self.name.clear_rules();
2776
2777        self.fill.clear_rules();
2778
2779        // Clear all custom property rule data on stylesheet reload
2780        for store in self.custom_color_props.values_mut() {
2781            store.clear_rules();
2782        }
2783        self.custom_color_props
2784            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
2785        for store in self.custom_length_props.values_mut() {
2786            store.clear_rules();
2787        }
2788        self.custom_length_props
2789            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
2790        for store in self.custom_font_size_props.values_mut() {
2791            store.clear_rules();
2792        }
2793        self.custom_font_size_props
2794            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
2795        for store in self.custom_units_props.values_mut() {
2796            store.clear_rules();
2797        }
2798        self.custom_units_props
2799            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
2800        for store in self.custom_opacity_props.values_mut() {
2801            store.clear_rules();
2802        }
2803        self.custom_opacity_props
2804            .retain(|_, store| !store.shared_data.is_empty() || !store.inline_data.is_empty());
2805    }
2806}