1use 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 #[derive(Debug, Clone, Copy)]
110 pub(crate) struct Abilities: u8 {
111 const HOVERABLE = 1 << 0;
113 const FOCUSABLE = 1 << 1;
115 const CHECKABLE = 1 << 2;
117 const NAVIGABLE = 1 << 3;
119 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#[derive(Debug, Clone, PartialEq)]
150pub enum ImageOrGradient {
151 Image(String),
153 Gradient(Gradient),
155}
156
157#[derive(Debug, Clone, PartialEq, Eq)]
159pub enum FamilyOwned {
160 Generic(GenericFontFamily),
162 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 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#[derive(Default)]
196pub struct Style {
197 pub(crate) rule_manager: IdManager<Rule>,
198
199 pub(crate) animation_manager: IdManager<Animation>,
201 pub(crate) animations: HashMap<String, Animation>,
202 pub(crate) pending_animations: Vec<(Entity, Animation, Duration, Duration)>,
204
205 pub(crate) rules: IndexMap<Rule, StyleRule>,
207
208 pub(crate) default_font: Vec<FamilyOwned>,
209
210 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 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 pub(crate) visibility: StyleSet<Visibility>,
235
236 pub(crate) opacity: AnimatableVarSet<Opacity>,
238
239 pub(crate) z_index: StyleSet<i32>,
241
242 pub(crate) clip_path: AnimatableSet<ClipPath>,
244
245 pub(crate) overflowx: StyleSet<Overflow>,
247 pub(crate) overflowy: StyleSet<Overflow>,
248
249 pub(crate) filter: AnimatableSet<Filter>,
251 pub(crate) backdrop_filter: AnimatableSet<Filter>,
252
253 pub(crate) blend_mode: StyleSet<BlendMode>,
254
255 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 pub(crate) border_width: AnimatableVarSet<LengthOrPercentage>,
264 pub(crate) border_color: AnimatableVarSet<Color>,
265 pub(crate) border_style: StyleSet<BorderStyleKeyword>,
266
267 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 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 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 pub(crate) outline_width: AnimatableVarSet<LengthOrPercentage>,
287 pub(crate) outline_color: AnimatableVarSet<Color>,
288 pub(crate) outline_offset: AnimatableVarSet<LengthOrPercentage>,
289
290 pub(crate) background_color: AnimatableVarSet<Color>,
292 pub(crate) background_image: AnimatableSet<Vec<ImageOrGradient>>,
293 pub(crate) background_size: AnimatableSet<Vec<BackgroundSize>>,
294
295 pub(crate) shadow: AnimatableVarSet<Vec<Shadow>>,
297
298 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 pub(crate) cursor: StyleSet<CursorIcon>,
327
328 pub(crate) pointer_events: StyleSet<PointerEvents>,
329
330 pub(crate) display: AnimatableSet<Display>,
334
335 pub(crate) layout_type: StyleSet<LayoutType>,
337
338 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 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 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 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 pub(crate) vertical_scroll: AnimatableSet<f32>,
370 pub(crate) horizontal_scroll: AnimatableSet<f32>,
371
372 pub(crate) width: AnimatableVarSet<Units>,
374 pub(crate) height: AnimatableVarSet<Units>,
375
376 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 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 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 pub fn scale_factor(&self) -> f32 {
414 self.dpi_factor as f32
415 }
416
417 pub fn logical_to_physical(&self, logical: f32) -> f32 {
419 (logical * self.dpi_factor as f32).round()
420 }
421
422 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 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 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 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 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 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 Property::Shadow(value) => {
608 insert_keyframe2(&mut self.shadow, animation_id, time, value.clone());
609 }
610
611 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 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 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 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 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 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 for store in self.custom_color_props.values_mut() {
844 store.play_animation(entity, animation, start_time, duration, delay);
845 }
846 for store in self.custom_length_props.values_mut() {
848 store.play_animation(entity, animation, start_time, duration, delay);
849 }
850 for store in self.custom_units_props.values_mut() {
852 store.play_animation(entity, animation, start_time, duration, delay);
853 }
854 for store in self.custom_opacity_props.values_mut() {
856 store.play_animation(entity, animation, start_time, duration, delay);
857 }
858 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 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 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 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 Property::Display(display) => {
1504 self.display.insert_rule(rule_id, display);
1505 }
1506
1507 Property::Visibility(visibility) => {
1509 self.visibility.insert_rule(rule_id, visibility);
1510 }
1511
1512 Property::Opacity(opacity) => {
1514 self.opacity.insert_rule(rule_id, opacity);
1515 }
1516
1517 Property::ClipPath(clip) => {
1519 self.clip_path.insert_rule(rule_id, clip);
1520 }
1521
1522 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 Property::BlendMode(blend_mode) => {
1533 self.blend_mode.insert_rule(rule_id, blend_mode);
1534 }
1535
1536 Property::LayoutType(layout_type) => {
1538 self.layout_type.insert_rule(rule_id, layout_type);
1539 }
1540
1541 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 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 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 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 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 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 Property::BackgroundColor(color) => {
1712 self.background_color.insert_rule(rule_id, color);
1713 }
1714
1715 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 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 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 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 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 Property::FontColor(font_color) => {
1807 self.font_color.insert_rule(rule_id, font_color);
1808 }
1809
1810 Property::FontSize(font_size) => {
1812 self.font_size.insert_rule(rule_id, font_size);
1813 }
1814
1815 Property::FontWeight(font_weight) => {
1817 self.font_weight.insert_rule(rule_id, font_weight);
1818 }
1819
1820 Property::FontSlant(font_slant) => {
1822 self.font_slant.insert_rule(rule_id, font_slant);
1823 }
1824
1825 Property::FontWidth(font_width) => {
1827 self.font_width.insert_rule(rule_id, font_width);
1828 }
1829
1830 Property::FontVariationSettings(font_variation_settings) => {
1832 self.font_variation_settings.insert_rule(rule_id, font_variation_settings);
1833 }
1834
1835 Property::CaretColor(caret_color) => {
1837 self.caret_color.insert_rule(rule_id, caret_color);
1838 }
1839
1840 Property::SelectionColor(selection_color) => {
1842 self.selection_color.insert_rule(rule_id, selection_color);
1843 }
1844
1845 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 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 Property::ZIndex(z_index) => self.z_index.insert_rule(rule_id, z_index),
1884
1885 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 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 Property::BackgroundSize(sizes) => {
1928 self.background_size.insert_rule(rule_id, sizes);
1929 }
1930
1931 Property::TextWrap(text_wrap) => {
1933 self.text_wrap.insert_rule(rule_id, text_wrap);
1934 }
1935
1936 Property::TextAlign(text_align) => {
1938 self.text_align.insert_rule(rule_id, text_align);
1939 }
1940
1941 Property::Shadow(shadows) => {
1943 self.shadow.insert_rule(rule_id, shadows);
1944 }
1945
1946 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 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 for token in custom.value.0.iter() {
2151 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 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 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 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 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 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 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 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 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 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 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 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.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 self.display.remove(entity);
2444 self.visibility.remove(entity);
2446 self.opacity.remove(entity);
2448 self.z_index.remove(entity);
2450 self.clip_path.remove(entity);
2452
2453 self.overflowx.remove(entity);
2454 self.overflowy.remove(entity);
2455
2456 self.filter.remove(entity);
2458 self.backdrop_filter.remove(entity);
2459
2460 self.blend_mode.remove(entity);
2462
2463 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 self.border_width.remove(entity);
2472 self.border_color.remove(entity);
2473 self.border_style.remove(entity);
2474
2475 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 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 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 self.outline_width.remove(entity);
2495 self.outline_color.remove(entity);
2496 self.outline_offset.remove(entity);
2497
2498 self.background_color.remove(entity);
2500 self.background_image.remove(entity);
2501 self.background_size.remove(entity);
2502
2503 self.shadow.remove(entity);
2505
2506 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 self.cursor.remove(entity);
2527
2528 self.pointer_events.remove(entity);
2529
2530 self.layout_type.remove(entity);
2532
2533 self.position_type.remove(entity);
2535
2536 self.alignment.remove(entity);
2537 self.direction.remove(entity);
2538 self.wrap.remove(entity);
2539
2540 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 self.left.remove(entity);
2550 self.right.remove(entity);
2551 self.top.remove(entity);
2552 self.bottom.remove(entity);
2553
2554 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 self.vertical_scroll.remove(entity);
2564 self.horizontal_scroll.remove(entity);
2565
2566 self.width.remove(entity);
2568 self.height.remove(entity);
2569
2570 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 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(crate) fn clear_style_rules(&mut self) {
2644 self.disabled.clear_rules();
2645 self.display.clear_rules();
2647 self.visibility.clear_rules();
2649 self.opacity.clear_rules();
2651 self.z_index.clear_rules();
2653
2654 self.clip_path.clear_rules();
2656
2657 self.filter.clear_rules();
2659 self.backdrop_filter.clear_rules();
2660
2661 self.blend_mode.clear_rules();
2663
2664 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 self.border_width.clear_rules();
2676 self.border_color.clear_rules();
2677 self.border_style.clear_rules();
2678
2679 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 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 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 self.outline_width.clear_rules();
2699 self.outline_color.clear_rules();
2700 self.outline_offset.clear_rules();
2701
2702 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 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 self.left.clear_rules();
2723 self.right.clear_rules();
2724 self.top.clear_rules();
2725 self.bottom.clear_rules();
2726
2727 self.width.clear_rules();
2729 self.height.clear_rules();
2730
2731 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 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 self.horizontal_scroll.clear_rules();
2752 self.vertical_scroll.clear_rules();
2753
2754 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 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}