css_ast/types/
animateable_feature.rs

1use css_parse::{Build, Cursor, Parser, T};
2use csskit_derives::{IntoCursor, Peek, ToCursors, Visitable};
3
4// https://drafts.csswg.org/css-will-change-1/#typedef-animateable-feature
5// <animateable-feature> = scroll-position | contents | <custom-ident>
6#[derive(IntoCursor, Peek, ToCursors, Visitable, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(rename_all = "kebab-case"))]
8#[visit(self)]
9pub enum AnimateableFeature {
10	ScrollPosition(T![Ident]),
11	Contents(T![Ident]),
12	CustomIdent(T![Ident]),
13
14	// These are known "custom idents" that Firefox, Safari and WebKit support.
15	// See https://searchfox.org/mozilla-central/source/servo/components/style/values/specified/box.rs#1001-1025
16	// and also https://searchfox.org/mozilla-central/source/servo/components/style/values/specified/box.rs#1033-1053
17	// for Firefox.
18	//
19	// See https://searchfox.org/wubkat/source/Source/WebCore/rendering/style/WillChangeData.cpp for Safari
20	//
21	// See https://source.chromium.org/search?q=%22WillChangeProperties().Contains%22
22	// and also https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/style/computed_style.cc;l=1366-1400
23	// for Chromium
24
25	// Shared
26	BackdropFilter(T![Ident]),
27	ClipPath(T![Ident]),
28	Contain(T![Ident]),
29	Filter(T![Ident]),
30	Isolation(T![Ident]),
31	MixBlendMode(T![Ident]),
32	OffsetPath(T![Ident]),
33	Opacity(T![Ident]),
34	Perspective(T![Ident]),
35	Position(T![Ident]),
36	Rotate(T![Ident]),
37	Scale(T![Ident]),
38	Transform(T![Ident]),
39	TransformStyle(T![Ident]),
40	Translate(T![Ident]),
41	ZIndex(T![Ident]),
42
43	// Chrome also supports
44	ViewTransitionName(T![Ident]),
45
46	// Chrome & Safari (but not Firefox) support
47	Mask(T![Ident]),
48	OffsetPosition(T![Ident]),
49	WebkitBoxReflect(T![Ident]),
50	WebkitMaskBoxImage(T![Ident]),
51
52	// Safari also supports
53	MaskBorder(T![Ident]),
54	WebkitMask(T![Ident]),
55	WebkitPerspective(T![Ident]),
56	WebkitBackdropFilter(T![Ident]),
57	WebkitOverflowScrolling(T![Ident]),
58
59	// Firefox & Safari also supports:
60	MaskImage(T![Ident]),
61}
62
63impl AnimateableFeature {
64	const MAP: phf::Map<&'static str, AnimateableFeature> = phf::phf_map! {
65			"-webkit-backdrop-filter" => Self::WebkitBackdropFilter(<T![Ident]>::dummy()),
66			"-webkit-box-reflex" => Self::WebkitBoxReflect(<T![Ident]>::dummy()),
67			"-webkit-mask" => Self::WebkitMask(<T![Ident]>::dummy()),
68			"-webkit-mask-box-image" => Self::WebkitMaskBoxImage(<T![Ident]>::dummy()),
69			"-webkit-overflow-scrolling" => Self::WebkitOverflowScrolling(<T![Ident]>::dummy()),
70			"-webkit-perspective" => Self::WebkitPerspective(<T![Ident]>::dummy()),
71			"backdrop-filter" => Self::BackdropFilter(<T![Ident]>::dummy()),
72			"clip-path" => Self::ClipPath(<T![Ident]>::dummy()),
73			"contain" => Self::Contain(<T![Ident]>::dummy()),
74			"filter" => Self::Filter(<T![Ident]>::dummy()),
75			"isolation" => Self::Isolation(<T![Ident]>::dummy()),
76			"mask" => Self::Mask(<T![Ident]>::dummy()),
77			"mask-border" => Self::MaskBorder(<T![Ident]>::dummy()),
78			"mask-image" => Self::MaskImage(<T![Ident]>::dummy()),
79			"mix-blend-mode" => Self::MixBlendMode(<T![Ident]>::dummy()),
80			"offset-path" => Self::OffsetPath(<T![Ident]>::dummy()),
81			"offset-position" => Self::OffsetPosition(<T![Ident]>::dummy()),
82			"opacity" => Self::Opacity(<T![Ident]>::dummy()),
83			"perspective" => Self::Perspective(<T![Ident]>::dummy()),
84			"position" => Self::Position(<T![Ident]>::dummy()),
85			"rotate" => Self::Rotate(<T![Ident]>::dummy()),
86			"scale" => Self::Scale(<T![Ident]>::dummy()),
87			"transform" => Self::Transform(<T![Ident]>::dummy()),
88			"transform-style" => Self::TransformStyle(<T![Ident]>::dummy()),
89			"translate" => Self::Translate(<T![Ident]>::dummy()),
90			"view-transition-name" => Self::ViewTransitionName(<T![Ident]>::dummy()),
91			"z-index" => Self::ZIndex(<T![Ident]>::dummy()),
92	};
93}
94
95impl<'a> Build<'a> for AnimateableFeature {
96	fn build(p: &Parser<'a>, c: Cursor) -> Self {
97		let ident = <T![Ident]>::build(p, c);
98		let feature = Self::MAP.get(p.parse_str_lower(c));
99		match feature {
100			Some(Self::WebkitBackdropFilter(_)) => Self::WebkitBackdropFilter(ident),
101			Some(Self::WebkitBoxReflect(_)) => Self::WebkitBoxReflect(ident),
102			Some(Self::WebkitMask(_)) => Self::WebkitMask(ident),
103			Some(Self::WebkitMaskBoxImage(_)) => Self::WebkitMaskBoxImage(ident),
104			Some(Self::WebkitOverflowScrolling(_)) => Self::WebkitOverflowScrolling(ident),
105			Some(Self::WebkitPerspective(_)) => Self::WebkitPerspective(ident),
106			Some(Self::BackdropFilter(_)) => Self::BackdropFilter(ident),
107			Some(Self::ClipPath(_)) => Self::ClipPath(ident),
108			Some(Self::Contain(_)) => Self::Contain(ident),
109			Some(Self::Filter(_)) => Self::Filter(ident),
110			Some(Self::Isolation(_)) => Self::Isolation(ident),
111			Some(Self::Mask(_)) => Self::Mask(ident),
112			Some(Self::MaskBorder(_)) => Self::MaskBorder(ident),
113			Some(Self::MaskImage(_)) => Self::MaskImage(ident),
114			Some(Self::MixBlendMode(_)) => Self::MixBlendMode(ident),
115			Some(Self::OffsetPath(_)) => Self::OffsetPath(ident),
116			Some(Self::OffsetPosition(_)) => Self::OffsetPosition(ident),
117			Some(Self::Opacity(_)) => Self::Opacity(ident),
118			Some(Self::Perspective(_)) => Self::Perspective(ident),
119			Some(Self::Position(_)) => Self::Position(ident),
120			Some(Self::Rotate(_)) => Self::Rotate(ident),
121			Some(Self::Scale(_)) => Self::Scale(ident),
122			Some(Self::Transform(_)) => Self::Transform(ident),
123			Some(Self::TransformStyle(_)) => Self::TransformStyle(ident),
124			Some(Self::Translate(_)) => Self::Translate(ident),
125			Some(Self::ViewTransitionName(_)) => Self::ViewTransitionName(ident),
126			Some(Self::ZIndex(_)) => Self::ZIndex(ident),
127			_ => Self::CustomIdent(ident),
128		}
129	}
130}