1use crate::{
16 ElementId,
17 style::{StyleClassRef, StyleSelector, StyleSelectors},
18};
19
20use bitflags::bitflags;
21use smallvec::SmallVec;
22
23bitflags! {
24 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
25 pub struct StyleReasonFlags: u32 {
26 const SELECTOR = 1 << 0;
30
31 const ANIMATION = 1 << 1;
35
36 const TRANSITION = 1 << 2;
40
41 const TARGET = 1 << 3;
49
50 const STYLE_PASS = 1 << 4;
52
53 const VIEW_STYLE = 1 << 5;
55
56 const VISIBILITY = 1 << 6;
58
59 const INHERITED_CHANGE = 1 << 7;
63
64 const CLASS_CONTEXT_CHANGE = 1 << 8;
68
69 }
70}
71
72#[derive(Clone, Debug)]
82pub struct StyleReason {
83 pub flags: StyleReasonFlags,
84
85 pub selectors: Option<StyleSelectors>,
90
91 pub classes_changed: Option<SmallVec<[StyleClassRef; 4]>>,
92
93 pub targets: Vec<(crate::ElementId, StyleReason)>,
103}
104
105impl StyleReason {
106 pub fn empty() -> Self {
107 Self {
108 flags: StyleReasonFlags::empty(),
109 selectors: None,
110 classes_changed: None,
111 targets: Vec::new(),
112 }
113 }
114
115 pub fn with_selectors(selectors: StyleSelectors) -> Self {
116 let mut s = Self::empty();
117 s.set_selectors(selectors);
118 s
119 }
120
121 pub fn with_selector(selector: StyleSelector) -> Self {
122 let mut s = Self::empty();
123 s.set_selectors(StyleSelectors::empty().set_selector(selector, true));
124 s
125 }
126
127 pub fn is_empty(&self) -> bool {
128 self.flags.is_empty()
129 }
130
131 pub fn set_inherited(&mut self) {
134 self.flags |= StyleReasonFlags::INHERITED_CHANGE;
135 }
136
137 pub fn set_class_cx(&mut self) {
138 self.flags |= StyleReasonFlags::CLASS_CONTEXT_CHANGE;
139 }
140
141 pub fn set_animation(&mut self) {
142 self.flags |= StyleReasonFlags::ANIMATION;
143 }
144
145 pub fn set_transition(&mut self) {
146 self.flags |= StyleReasonFlags::TRANSITION;
147 }
148
149 pub fn set_style_pass(&mut self) {
150 self.flags |= StyleReasonFlags::STYLE_PASS;
151 }
152
153 pub fn set_view_style(&mut self) {
154 self.flags |= StyleReasonFlags::VIEW_STYLE;
155 }
156
157 pub fn set_visibility(&mut self) {
158 self.flags |= StyleReasonFlags::VISIBILITY;
159 }
160
161 pub fn set_selectors(&mut self, selectors: StyleSelectors) {
162 self.flags |= StyleReasonFlags::SELECTOR;
163 self.selectors = Some(selectors);
164 }
165
166 pub fn add_target(&mut self, id: crate::ElementId, reason: StyleReason) {
167 self.flags |= StyleReasonFlags::TARGET;
168 self.targets.push((id, reason));
169 }
170
171 pub fn animation() -> Self {
172 let mut s = Self::empty();
173 s.set_animation();
174 s
175 }
176
177 pub fn style_pass() -> Self {
178 let mut s = Self::empty();
179 s.set_style_pass();
180 s
181 }
182
183 pub fn view_style() -> Self {
184 let mut s = Self::empty();
185 s.set_view_style();
186 s
187 }
188
189 pub fn visibility() -> Self {
190 let mut s = Self::empty();
191 s.set_visibility();
192 s
193 }
194
195 pub fn transition() -> Self {
196 let mut s = Self::empty();
197 s.set_transition();
198 s
199 }
200
201 pub fn inherited() -> Self {
202 let mut s = Self::empty();
203 s.set_inherited();
204 s
205 }
206
207 pub fn class_cx(classes: SmallVec<[StyleClassRef; 4]>) -> Self {
208 let mut s = Self::empty();
209 s.set_class_cx();
210 s.classes_changed = Some(classes);
211 s
212 }
213
214 pub fn needs_resolve_nested_maps(&self) -> bool {
220 self.flags.intersects(
221 StyleReasonFlags::SELECTOR
222 | StyleReasonFlags::VIEW_STYLE
223 | StyleReasonFlags::CLASS_CONTEXT_CHANGE
224 | StyleReasonFlags::INHERITED_CHANGE,
225 )
226 }
227
228 pub fn needs_animation(&self) -> bool {
229 self.flags.intersects(StyleReasonFlags::ANIMATION)
230 }
231
232 pub fn needs_property_extraction(&self) -> bool {
233 self.needs_resolve_nested_maps()
234 || self.needs_animation()
235 || self.flags.intersects(StyleReasonFlags::TRANSITION)
236 || self.flags.intersects(StyleReasonFlags::INHERITED_CHANGE)
237 || self
238 .flags
239 .intersects(StyleReasonFlags::CLASS_CONTEXT_CHANGE)
240 }
241
242 pub fn has_animation(&self) -> bool {
243 self.flags.contains(StyleReasonFlags::ANIMATION)
244 }
245
246 pub fn has_visiblity(&self) -> bool {
247 self.flags.contains(StyleReasonFlags::VISIBILITY)
248 }
249
250 pub fn has_transition(&self) -> bool {
251 self.flags.contains(StyleReasonFlags::TRANSITION)
252 }
253
254 pub fn has_selector(&self) -> bool {
255 self.flags.contains(StyleReasonFlags::SELECTOR)
256 }
257
258 pub fn has_target(&self) -> bool {
259 self.flags.contains(StyleReasonFlags::TARGET)
260 }
261
262 pub fn has_target_id(&self, id: crate::ElementId) -> bool {
263 self.targets.iter().any(|(tid, _)| *tid == id)
264 }
265
266 pub fn target_reason(&self, id: crate::ElementId) -> Option<&StyleReason> {
267 self.targets
268 .iter()
269 .find(|(tid, _)| *tid == id)
270 .map(|(_, r)| r)
271 }
272
273 pub fn merge(&mut self, other: StyleReason) {
277 self.flags |= other.flags;
278
279 match (self.selectors, other.selectors) {
281 (Some(a), Some(b)) => self.selectors = Some(a | b),
282 (None, Some(b)) => self.selectors = Some(b),
283 _ => {}
284 }
285
286 match (&mut self.classes_changed, other.classes_changed) {
288 (Some(a), Some(b)) => {
289 for class in b {
290 if !a.contains(&class) {
291 a.push(class);
292 }
293 }
294 }
295 (None, Some(b)) => {
296 self.classes_changed = Some(b);
297 }
298 _ => {}
299 }
300
301 for (id, reason) in other.targets {
303 if let Some((_, existing)) = self.targets.iter_mut().find(|(tid, _)| *tid == id) {
304 existing.merge(reason);
305 } else {
306 self.targets.push((id, reason));
307 }
308 }
309 }
310
311 pub fn filter(&self, flags: StyleReasonFlags) -> StyleReason {
313 let mut out = StyleReason::empty();
314 let masked = self.flags & flags;
315 out.flags = masked;
316
317 if masked.contains(StyleReasonFlags::SELECTOR) {
318 out.selectors = self.selectors;
319 }
320 if masked.contains(StyleReasonFlags::TARGET) {
321 out.targets = self.targets.clone();
322 }
323 out
324 }
325
326 pub fn clear_flag(&mut self, flag: StyleReasonFlags) {
328 self.flags.remove(flag);
329 if flag.contains(StyleReasonFlags::SELECTOR) {
330 self.selectors = None;
331 }
332 if flag.contains(StyleReasonFlags::CLASS_CONTEXT_CHANGE) {
333 self.classes_changed = None;
334 }
335 if flag.contains(StyleReasonFlags::TARGET) {
336 self.targets.clear();
337 }
338 }
339
340 pub fn clear_target(&mut self, id: crate::ElementId) {
341 self.targets.retain(|(tid, _)| *tid != id);
342 if self.targets.is_empty() {
343 self.flags.remove(StyleReasonFlags::TARGET);
344 }
345 }
346
347 pub fn for_children(&self) -> StyleReason {
348 let mut out = self.clone();
349 out.targets.clear();
350 out.flags.remove(StyleReasonFlags::TARGET);
351 out.flags.remove(StyleReasonFlags::TRANSITION);
352 out.flags.remove(StyleReasonFlags::ANIMATION);
353 out.flags.remove(StyleReasonFlags::STYLE_PASS);
354 out.flags.remove(StyleReasonFlags::VIEW_STYLE);
355 out.flags.remove(StyleReasonFlags::VISIBILITY);
357
358 if let Some(selectors) = out.selectors {
359 let propagating = selectors.propagating();
360 if propagating.is_empty() {
361 out.selectors = None;
362 out.flags.remove(StyleReasonFlags::SELECTOR);
363 } else {
364 out.selectors = Some(propagating);
365 }
366 }
367
368 out
369 }
370
371 pub fn with_target(element_id: ElementId, reason: StyleReason) -> Self {
372 let mut s = Self::empty();
373 s.add_target(element_id, reason);
374 s
375 }
376
377 pub fn with_selectors_and_target(element_id: ElementId, selectors: StyleSelectors) -> Self {
378 let inner = StyleReason::with_selectors(selectors);
379 Self::with_target(element_id, inner)
380 }
381
382 pub fn full_recalc() -> Self {
385 Self {
386 flags: StyleReasonFlags::all(),
387 selectors: None,
388 targets: Vec::new(),
389 classes_changed: None,
390 }
391 }
392}