1extern crate alloc;
25
26use alloc::{boxed::Box, string::String, vec::Vec};
27use core::fmt::Write;
28use core::mem::ManuallyDrop;
29
30use crate::dom::NodeType;
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35pub enum CssPropertyOrigin {
36 Inherited,
38 Own,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct CssPropertyWithOrigin {
45 pub property: CssProperty,
46 pub origin: CssPropertyOrigin,
47}
48
49use azul_css::{
50 css::{Css, CssPath},
51 props::{
52 basic::{StyleFontFamily, StyleFontFamilyVec, StyleFontSize},
53 layout::{LayoutDisplay, LayoutHeight, LayoutWidth},
54 property::{
55 BoxDecorationBreakValue, BreakInsideValue, CaretAnimationDurationValue,
56 CaretColorValue, CaretWidthValue, ClipPathValue, ColumnCountValue, ColumnFillValue,
57 ColumnRuleColorValue, ColumnRuleStyleValue, ColumnRuleWidthValue, ColumnSpanValue,
58 ColumnWidthValue, ContentValue, CounterIncrementValue, CounterResetValue, CssProperty,
59 CssPropertyType, FlowFromValue, FlowIntoValue, LayoutAlignContentValue,
60 LayoutAlignItemsValue, LayoutAlignSelfValue, LayoutBorderBottomWidthValue,
61 LayoutBorderLeftWidthValue, LayoutBorderRightWidthValue, LayoutBorderSpacingValue,
62 LayoutBorderTopWidthValue, LayoutBoxSizingValue, LayoutClearValue,
63 LayoutColumnGapValue, LayoutDisplayValue, LayoutFlexBasisValue,
64 LayoutFlexDirectionValue, LayoutFlexGrowValue, LayoutFlexShrinkValue,
65 LayoutFlexWrapValue, LayoutFloatValue, LayoutGapValue, LayoutGridAutoColumnsValue,
66 LayoutGridAutoFlowValue, LayoutGridAutoRowsValue, LayoutGridColumnValue,
67 LayoutGridRowValue, LayoutGridTemplateColumnsValue, LayoutGridTemplateRowsValue,
68 LayoutHeightValue, LayoutInsetBottomValue, LayoutJustifyContentValue,
69 LayoutJustifyItemsValue, LayoutJustifySelfValue, LayoutLeftValue,
70 LayoutMarginBottomValue, LayoutMarginLeftValue, LayoutMarginRightValue,
71 LayoutMarginTopValue, LayoutMaxHeightValue, LayoutMaxWidthValue, LayoutMinHeightValue,
72 LayoutMinWidthValue, LayoutOverflowValue, LayoutPaddingBottomValue,
73 LayoutPaddingLeftValue, LayoutPaddingRightValue, LayoutPaddingTopValue,
74 LayoutPositionValue, LayoutRightValue, LayoutRowGapValue, LayoutScrollbarWidthValue,
75 LayoutTableLayoutValue, LayoutTextJustifyValue, LayoutTopValue, LayoutWidthValue,
76 LayoutWritingModeValue, LayoutZIndexValue, OrphansValue, OverscrollBehaviorValue,
77 PageBreakValue, ScrollbarFadeDelayValue, ScrollbarFadeDurationValue,
78 ScrollbarVisibilityModeValue, SelectionBackgroundColorValue, SelectionColorValue,
79 SelectionRadiusValue, ShapeImageThresholdValue, ShapeInsideValue, ShapeMarginValue,
80 ShapeOutsideValue, StringSetValue, StyleAlignmentBaselineValue, StyleAppRegionValue,
81 StyleSpatialNavigationActionValue, StyleSpatialNavigationContainValue,
82 StyleAspectRatioValue, StyleBackfaceVisibilityValue, StyleBackgroundContentValue,
83 StyleBackgroundContentVecValue, StyleBackgroundPositionVecValue,
84 StyleBackgroundRepeatVecValue, StyleBackgroundSizeVecValue, StyleBaselineSourceValue,
85 StyleBorderBottomColorValue, StyleBorderBottomLeftRadiusValue,
86 StyleBorderBottomRightRadiusValue, StyleBorderBottomStyleValue,
87 StyleBorderCollapseValue, StyleBorderLeftColorValue, StyleBorderLeftStyleValue,
88 StyleBorderRightColorValue, StyleBorderRightStyleValue, StyleBorderTopColorValue,
89 StyleBorderTopLeftRadiusValue, StyleBorderTopRightRadiusValue,
90 StyleBorderTopStyleValue, StyleBoxShadowValue, StyleCaptionSideValue,
91 StyleClipRectValue, StyleCursorValue, StyleDirectionValue, StyleDominantBaselineValue,
92 StyleEmptyCellsValue, StyleExclusionMarginValue, StyleFilterVecValue,
93 StyleFontFamilyVecValue, StyleFontSizeValue, StyleFontStyleValue, StyleFontValue,
94 StyleFontWeightValue, StyleHangingPunctuationValue, StyleHyphenationLanguageValue,
95 StyleHyphensValue, StyleInitialLetterAlignValue, StyleInitialLetterValue,
96 StyleInitialLetterWrapValue, StyleLetterSpacingValue, StyleLineBreakValue,
97 StyleLineClampValue, StyleLineFitEdgeValue, StyleLineHeightValue,
98 StyleListStylePositionValue, StyleListStyleTypeValue, StyleMixBlendModeValue,
99 StyleObjectFitValue, StyleObjectPositionValue, StyleOpacityValue,
100 StyleOverflowClipMarginValue, StyleOverflowWrapValue, StylePerspectiveOriginValue,
101 StyleScrollbarColorValue, StyleScrollbarGutterValue, StyleTabSizeValue,
102 StyleTextAlignLastValue, StyleTextAlignValue, StyleTextBoxEdgeValue,
103 StyleTextBoxTrimValue, StyleTextColorValue, StyleTextCombineUprightValue,
104 StyleTextDecorationValue, StyleTextIndentValue, StyleTextOrientationValue,
105 StyleTextOverflowValue, StyleTextTransformValue, StyleTransformOriginValue,
106 StyleTransformVecValue, StyleUnicodeBidiValue, StyleUserSelectValue,
107 StyleVerticalAlignValue, StyleVisibilityValue, StyleWhiteSpaceValue,
108 StyleWordBreakValue, StyleWordSpacingValue, WidowsValue,
109 },
110 style::{StyleCursor, StyleTextColor, StyleTransformOrigin},
111 },
112 AzString,
113};
114
115use crate::{
116 dom::{NodeData, NodeId, TabIndex, TagId},
117 id::{NodeDataContainer, NodeDataContainerRef},
118 style::CascadeInfo,
119 styled_dom::{
120 NodeHierarchyItem, NodeHierarchyItemId, NodeHierarchyItemVec, ParentWithNodeDepth,
121 ParentWithNodeDepthVec, StyledNodeState, TagIdToNodeIdMapping,
122 },
123};
124
125use azul_css::dynamic_selector::{
126 CssPropertyWithConditions, CssPropertyWithConditionsVec, DynamicSelectorContext,
127};
128
129#[cfg(feature = "std")]
130std::thread_local! {
131 static PROP_COUNTS: core::cell::RefCell<
132 std::collections::HashMap<&'static str, usize>
133 > = core::cell::RefCell::new(std::collections::HashMap::new());
134}
135
136#[cfg(feature = "std")]
145#[must_use]
146pub fn drain_css_prop_counts() -> Vec<(&'static str, usize)> {
147 PROP_COUNTS
150 .try_with(|c| {
151 let map = core::mem::take(&mut *c.borrow_mut());
152 let mut v: Vec<_> = map.into_iter().collect();
153 v.sort_by(|a, b| b.1.cmp(&a.1));
154 v
155 })
156 .unwrap_or_default()
157}
158
159const PT_TO_PX: f32 = 1.333_333;
161const IN_TO_PX: f32 = 96.0;
162const CM_TO_PX: f32 = 37.795_277;
163const MM_TO_PX: f32 = 3.779_527_7;
164
165#[allow(unused_macros)]
167macro_rules! match_property_value {
168 ($property:expr, $value:ident, $expr:expr) => {
169 match $property {
170 CssProperty::CaretColor($value) => $expr,
171 CssProperty::CaretAnimationDuration($value) => $expr,
172 CssProperty::SelectionBackgroundColor($value) => $expr,
173 CssProperty::SelectionColor($value) => $expr,
174 CssProperty::SelectionRadius($value) => $expr,
175 CssProperty::TextColor($value) => $expr,
176 CssProperty::FontSize($value) => $expr,
177 CssProperty::FontFamily($value) => $expr,
178 CssProperty::FontWeight($value) => $expr,
179 CssProperty::FontStyle($value) => $expr,
180 CssProperty::TextAlign($value) => $expr,
181 CssProperty::TextJustify($value) => $expr,
182 CssProperty::VerticalAlign($value) => $expr,
183 CssProperty::LetterSpacing($value) => $expr,
184 CssProperty::TextIndent($value) => $expr,
185 CssProperty::InitialLetter($value) => $expr,
186 CssProperty::LineClamp($value) => $expr,
187 CssProperty::HangingPunctuation($value) => $expr,
188 CssProperty::TextCombineUpright($value) => $expr,
189 CssProperty::UnicodeBidi($value) => $expr,
190 CssProperty::TextBoxTrim($value) => $expr,
191 CssProperty::TextBoxEdge($value) => $expr,
192 CssProperty::DominantBaseline($value) => $expr,
193 CssProperty::AlignmentBaseline($value) => $expr,
194 CssProperty::BaselineSource($value) => $expr,
195 CssProperty::LineFitEdge($value) => $expr,
196 CssProperty::InitialLetterAlign($value) => $expr,
197 CssProperty::InitialLetterWrap($value) => $expr,
198 CssProperty::ScrollbarGutter($value) => $expr,
199 CssProperty::OverflowClipMargin($value) => $expr,
200 CssProperty::Clip($value) => $expr,
201 CssProperty::ExclusionMargin($value) => $expr,
202 CssProperty::HyphenationLanguage($value) => $expr,
203 CssProperty::LineHeight($value) => $expr,
204 CssProperty::WordSpacing($value) => $expr,
205 CssProperty::TabSize($value) => $expr,
206 CssProperty::WhiteSpace($value) => $expr,
207 CssProperty::Hyphens($value) => $expr,
208 CssProperty::Direction($value) => $expr,
209 CssProperty::UserSelect($value) => $expr,
210 CssProperty::TextDecoration($value) => $expr,
211 CssProperty::Cursor($value) => $expr,
212 CssProperty::Display($value) => $expr,
213 CssProperty::Float($value) => $expr,
214 CssProperty::BoxSizing($value) => $expr,
215 CssProperty::Width($value) => $expr,
216 CssProperty::Height($value) => $expr,
217 CssProperty::MinWidth($value) => $expr,
218 CssProperty::MinHeight($value) => $expr,
219 CssProperty::MaxWidth($value) => $expr,
220 CssProperty::MaxHeight($value) => $expr,
221 CssProperty::Position($value) => $expr,
222 CssProperty::Top($value) => $expr,
223 CssProperty::Right($value) => $expr,
224 CssProperty::Left($value) => $expr,
225 CssProperty::Bottom($value) => $expr,
226 CssProperty::ZIndex($value) => $expr,
227 CssProperty::FlexWrap($value) => $expr,
228 CssProperty::FlexDirection($value) => $expr,
229 CssProperty::FlexGrow($value) => $expr,
230 CssProperty::FlexShrink($value) => $expr,
231 CssProperty::FlexBasis($value) => $expr,
232 CssProperty::JustifyContent($value) => $expr,
233 CssProperty::AlignItems($value) => $expr,
234 CssProperty::AlignContent($value) => $expr,
235 CssProperty::AlignSelf($value) => $expr,
236 CssProperty::JustifyItems($value) => $expr,
237 CssProperty::JustifySelf($value) => $expr,
238 CssProperty::BackgroundContent($value) => $expr,
239 CssProperty::BackgroundPosition($value) => $expr,
240 CssProperty::BackgroundSize($value) => $expr,
241 CssProperty::BackgroundRepeat($value) => $expr,
242 CssProperty::OverflowX($value) => $expr,
243 CssProperty::OverflowY($value) => $expr,
244 CssProperty::OverflowBlock($value) => $expr,
245 CssProperty::OverflowInline($value) => $expr,
246 CssProperty::PaddingTop($value) => $expr,
247 CssProperty::PaddingLeft($value) => $expr,
248 CssProperty::PaddingRight($value) => $expr,
249 CssProperty::PaddingBottom($value) => $expr,
250 CssProperty::MarginTop($value) => $expr,
251 CssProperty::MarginLeft($value) => $expr,
252 CssProperty::MarginRight($value) => $expr,
253 CssProperty::MarginBottom($value) => $expr,
254 CssProperty::BorderTopLeftRadius($value) => $expr,
255 CssProperty::BorderTopRightRadius($value) => $expr,
256 CssProperty::BorderBottomLeftRadius($value) => $expr,
257 CssProperty::BorderBottomRightRadius($value) => $expr,
258 CssProperty::BorderTopColor($value) => $expr,
259 CssProperty::BorderRightColor($value) => $expr,
260 CssProperty::BorderLeftColor($value) => $expr,
261 CssProperty::BorderBottomColor($value) => $expr,
262 CssProperty::BorderTopStyle($value) => $expr,
263 CssProperty::BorderRightStyle($value) => $expr,
264 CssProperty::BorderLeftStyle($value) => $expr,
265 CssProperty::BorderBottomStyle($value) => $expr,
266 CssProperty::BorderTopWidth($value) => $expr,
267 CssProperty::BorderRightWidth($value) => $expr,
268 CssProperty::BorderLeftWidth($value) => $expr,
269 CssProperty::BorderBottomWidth($value) => $expr,
270 CssProperty::BoxShadow($value) => $expr,
271 CssProperty::Opacity($value) => $expr,
272 CssProperty::Transform($value) => $expr,
273 CssProperty::TransformOrigin($value) => $expr,
274 CssProperty::PerspectiveOrigin($value) => $expr,
275 CssProperty::BackfaceVisibility($value) => $expr,
276 CssProperty::MixBlendMode($value) => $expr,
277 CssProperty::Filter($value) => $expr,
278 CssProperty::Visibility($value) => $expr,
279 CssProperty::WritingMode($value) => $expr,
280 CssProperty::GridTemplateColumns($value) => $expr,
281 CssProperty::GridTemplateRows($value) => $expr,
282 CssProperty::GridAutoColumns($value) => $expr,
283 CssProperty::GridAutoRows($value) => $expr,
284 CssProperty::GridAutoFlow($value) => $expr,
285 CssProperty::GridColumn($value) => $expr,
286 CssProperty::GridRow($value) => $expr,
287 CssProperty::GridTemplateAreas($value) => $expr,
288 CssProperty::Gap($value) => $expr,
289 CssProperty::ColumnGap($value) => $expr,
290 CssProperty::RowGap($value) => $expr,
291 CssProperty::Clear($value) => $expr,
292 CssProperty::ScrollbarTrack($value) => $expr,
293 CssProperty::ScrollbarThumb($value) => $expr,
294 CssProperty::ScrollbarButton($value) => $expr,
295 CssProperty::ScrollbarCorner($value) => $expr,
296 CssProperty::ScrollbarResizer($value) => $expr,
297 CssProperty::ScrollbarWidth($value) => $expr,
298 CssProperty::ScrollbarColor($value) => $expr,
299 CssProperty::ListStyleType($value) => $expr,
300 CssProperty::ListStylePosition($value) => $expr,
301 CssProperty::Font($value) => $expr,
302 CssProperty::ColumnCount($value) => $expr,
303 CssProperty::ColumnWidth($value) => $expr,
304 CssProperty::ColumnSpan($value) => $expr,
305 CssProperty::ColumnFill($value) => $expr,
306 CssProperty::ColumnRuleStyle($value) => $expr,
307 CssProperty::ColumnRuleWidth($value) => $expr,
308 CssProperty::ColumnRuleColor($value) => $expr,
309 CssProperty::FlowInto($value) => $expr,
310 CssProperty::FlowFrom($value) => $expr,
311 CssProperty::ShapeOutside($value) => $expr,
312 CssProperty::ShapeInside($value) => $expr,
313 CssProperty::ShapeImageThreshold($value) => $expr,
314 CssProperty::ShapeMargin($value) => $expr,
315 CssProperty::ClipPath($value) => $expr,
316 CssProperty::Content($value) => $expr,
317 CssProperty::CounterIncrement($value) => $expr,
318 CssProperty::CounterReset($value) => $expr,
319 CssProperty::StringSet($value) => $expr,
320 CssProperty::Orphans($value) => $expr,
321 CssProperty::Widows($value) => $expr,
322 CssProperty::PageBreakBefore($value) => $expr,
323 CssProperty::PageBreakAfter($value) => $expr,
324 CssProperty::PageBreakInside($value) => $expr,
325 CssProperty::BreakInside($value) => $expr,
326 CssProperty::BoxDecorationBreak($value) => $expr,
327 CssProperty::TableLayout($value) => $expr,
328 CssProperty::BorderCollapse($value) => $expr,
329 CssProperty::BorderSpacing($value) => $expr,
330 CssProperty::CaptionSide($value) => $expr,
331 CssProperty::EmptyCells($value) => $expr,
332 }
333 };
334}
335
336#[derive(Debug, Clone, PartialEq, Eq)]
342pub struct StatefulCssProperty {
343 pub state: azul_css::dynamic_selector::PseudoStateType,
344 pub prop_type: CssPropertyType,
345 pub property: CssProperty,
346}
347
348#[derive(Debug, Clone)]
367pub struct FlatVecVec<T> {
368 build: Vec<Vec<T>>,
370 data: Vec<T>,
372 offsets: Vec<(u32, u32)>,
374}
375
376impl<T: PartialEq> PartialEq for FlatVecVec<T> {
377 fn eq(&self, other: &Self) -> bool {
378 let self_in_build = !self.build.is_empty() && self.offsets.is_empty();
379 let other_in_build = !other.build.is_empty() && other.offsets.is_empty();
380 debug_assert!(
381 self_in_build == other_in_build,
382 "FlatVecVec::eq called across phases (one build, one flattened)"
383 );
384 if self_in_build || other_in_build {
385 self.build == other.build
386 } else {
387 self.data == other.data && self.offsets == other.offsets
388 }
389 }
390}
391
392impl<T> Default for FlatVecVec<T> {
393 fn default() -> Self {
394 Self {
395 build: Vec::new(),
396 data: Vec::new(),
397 offsets: Vec::new(),
398 }
399 }
400}
401
402impl<T> FlatVecVec<T> {
403 #[must_use]
408 pub fn heap_bytes(&self, per_element_size: usize) -> usize {
409 let data_bytes = self.data.capacity() * per_element_size;
410 let offsets_bytes = self.offsets.capacity() * size_of::<(u32, u32)>();
411 let mut build_bytes = self.build.capacity() * size_of::<Vec<T>>();
412 for v in &self.build {
413 build_bytes += v.capacity() * per_element_size;
414 }
415 data_bytes + offsets_bytes + build_bytes
416 }
417
418 #[must_use]
420 pub fn new(node_count: usize) -> Self {
421 let mut build = Vec::with_capacity(node_count);
422 for _ in 0..node_count {
423 build.push(Vec::new());
424 }
425 Self {
426 build,
427 data: Vec::new(),
428 offsets: Vec::new(),
429 }
430 }
431
432 #[inline]
437 pub fn push_to(&mut self, node_index: usize, item: T) {
438 self.build[node_index].push(item);
439 }
440
441 #[inline]
443 pub fn build_mut(&mut self, node_index: usize) -> &mut Vec<T> {
444 &mut self.build[node_index]
445 }
446
447 #[inline]
449 pub fn build_iter_mut(&mut self) -> core::slice::IterMut<'_, Vec<T>> {
450 self.build.iter_mut()
451 }
452
453 #[inline]
456 #[must_use]
457 pub fn build_get(&self, node_index: usize) -> Option<&Vec<T>> {
458 self.build.get(node_index)
459 }
460
461 #[inline]
463 #[must_use]
464 pub const fn len(&self) -> usize {
465 if self.offsets.is_empty() {
466 self.build.len()
467 } else {
468 self.offsets.len()
469 }
470 }
471
472 #[inline]
474 #[must_use]
475 pub const fn is_empty(&self) -> bool {
476 self.len() == 0
477 }
478
479 #[inline]
481 #[must_use]
482 pub const fn is_flattened(&self) -> bool {
483 !self.offsets.is_empty() || self.build.is_empty()
484 }
485
486 #[inline]
490 #[must_use]
491 pub fn get_slice(&self, node_index: usize) -> &[T] {
492 if self.offsets.is_empty() {
493 self.build
495 .get(node_index)
496 .map_or(&[], alloc::vec::Vec::as_slice)
497 } else {
498 if let Some(&(start, len)) = self.offsets.get(node_index) {
500 let s = start as usize;
501 let l = len as usize;
502 &self.data[s..s + l]
503 } else {
504 &[]
505 }
506 }
507 }
508
509 fn dedup_runs(&mut self)
534 where
535 T: Clone + PartialEq,
536 {
537 const MAX_RUNS: usize = 1024;
540
541 if self.offsets.is_empty() {
542 return;
543 }
544 let mut new_data: Vec<T> = Vec::new();
545 let mut runs: Vec<(u32, u32)> = Vec::new();
546 let mut new_offsets = Vec::with_capacity(self.offsets.len());
547
548 for &(start, len) in &self.offsets {
549 if len == 0 {
550 new_offsets.push((0, 0));
551 continue;
552 }
553 let s = start as usize;
554 let run = &self.data[s..s + len as usize];
555 let existing = runs.iter().copied().find(|&(rs, rl)| {
556 rl == len && new_data[rs as usize..(rs + rl) as usize] == *run
557 });
558 if let Some((rs, rl)) = existing {
559 new_offsets.push((rs, rl));
560 continue;
561 }
562 let ns = u32::try_from(new_data.len()).unwrap_or(u32::MAX);
563 new_data.extend_from_slice(run);
564 if runs.len() < MAX_RUNS {
565 runs.push((ns, len));
566 }
567 new_offsets.push((ns, len));
568 }
569
570 self.data = new_data;
571 self.offsets = new_offsets;
572 }
573
574 pub fn sort_each_and_flatten<K: Ord + Eq>(&mut self, key_fn: impl Fn(&T) -> K)
575 where
576 T: Clone + PartialEq,
577 {
578 let node_count = self.build.len();
579 let total: usize = self.build.iter().map(alloc::vec::Vec::len).sum();
580
581 let mut flat_data = Vec::with_capacity(total);
582 let mut offsets = Vec::with_capacity(node_count);
583
584 for inner in &mut self.build {
585 inner.sort_by_key(|a| key_fn(a));
586
587 let n = inner.len();
589 let mut keep = vec![false; n];
590 for i in 0..n {
591 if i + 1 >= n || key_fn(&inner[i]) != key_fn(&inner[i + 1]) {
592 keep[i] = true;
593 }
594 }
595
596 let start = u32::try_from(flat_data.len()).unwrap_or(u32::MAX);
597 for (i, item) in inner.drain(..).enumerate() {
599 if keep[i] {
600 flat_data.push(item);
601 }
602 }
603
604 let len = u32::try_from(flat_data.len()).unwrap_or(u32::MAX) - start;
605 offsets.push((start, len));
606 }
607
608 flat_data.shrink_to_fit();
609 self.data = flat_data;
610 self.offsets = offsets;
611 self.build = Vec::new();
612 self.dedup_runs();
613 }
614
615 pub fn flatten(&mut self) {
617 let node_count = self.build.len();
618 let total: usize = self.build.iter().map(alloc::vec::Vec::len).sum();
619
620 let mut flat_data = Vec::with_capacity(total);
621 let mut offsets = Vec::with_capacity(node_count);
622
623 for inner in &mut self.build {
624 let start = u32::try_from(flat_data.len()).unwrap_or(u32::MAX);
625 let len = u32::try_from(inner.len()).unwrap_or(u32::MAX);
626 offsets.push((start, len));
627 flat_data.append(inner);
628 }
629
630 self.data = flat_data;
631 self.offsets = offsets;
632 self.build = Vec::new();
633 }
634
635 pub fn retain(&mut self, predicate: impl Fn(&T) -> bool)
638 where
639 T: Clone + PartialEq,
640 {
641 if self.offsets.is_empty() {
642 return;
643 }
644 let node_count = self.offsets.len();
645 let mut new_data = Vec::new();
646 let mut new_offsets = Vec::with_capacity(node_count);
647 for &(start, len) in &self.offsets {
648 let s = start as usize;
649 let l = len as usize;
650 let new_start = u32::try_from(new_data.len()).unwrap_or(u32::MAX);
651 let slice = &self.data[s..s + l];
652 let mut kept = 0u32;
653 for item in slice {
654 if predicate(item) {
655 new_data.push((*item).clone());
656 kept += 1;
657 }
658 }
659 new_offsets.push((new_start, kept));
660 }
661 new_data.shrink_to_fit();
662 self.data = new_data;
663 self.offsets = new_offsets;
664 self.dedup_runs();
665 }
666
667 pub fn ensure_build_phase(&mut self)
676 where
677 T: Clone,
678 {
679 if self.offsets.is_empty() {
680 return; }
682 let mut build = Vec::with_capacity(self.offsets.len());
683 for &(start, len) in &self.offsets {
684 let s = start as usize;
685 let l = len as usize;
686 build.push(self.data[s..s + l].to_vec());
687 }
688 self.build = build;
689 self.data = Vec::new();
690 self.offsets = Vec::new();
691 }
692
693 pub fn retain_with_node_index(&mut self, predicate: impl Fn(usize, &T) -> bool)
696 where
697 T: Clone,
698 {
699 if self.offsets.is_empty() {
700 return;
701 }
702 let node_count = self.offsets.len();
703 let mut new_data = Vec::new();
704 let mut new_offsets = Vec::with_capacity(node_count);
705 for (node_idx, &(start, len)) in self.offsets.iter().enumerate() {
706 let s = start as usize;
707 let l = len as usize;
708 let new_start = u32::try_from(new_data.len()).unwrap_or(u32::MAX);
709 let slice = &self.data[s..s + l];
710 let mut kept = 0u32;
711 for item in slice {
712 if predicate(node_idx, item) {
713 new_data.push((*item).clone());
714 kept += 1;
715 }
716 }
717 new_offsets.push((new_start, kept));
718 }
719 new_data.shrink_to_fit();
720 self.data = new_data;
721 self.offsets = new_offsets;
722 }
723
724 pub(crate) const fn iter_node_slices(&self) -> FlatVecVecIter<'_, T> {
727 FlatVecVecIter {
728 fvv: self,
729 idx: 0,
730 count: self.len(),
731 }
732 }
733
734 pub fn extend_from(&mut self, other: &mut Self) {
737 if !self.offsets.is_empty() && !other.offsets.is_empty() {
738 let base = u32::try_from(self.data.len()).unwrap_or(u32::MAX);
740 self.data.append(&mut other.data);
741 self.offsets
742 .extend(other.offsets.drain(..).map(|(s, l)| (s + base, l)));
743 } else {
744 self.build.append(&mut other.build);
746 self.data.clear();
748 self.offsets.clear();
749 }
750 }
751}
752
753pub(crate) struct FlatVecVecIter<'a, T> {
755 fvv: &'a FlatVecVec<T>,
756 idx: usize,
757 count: usize,
758}
759
760impl<'a, T> Iterator for FlatVecVecIter<'a, T> {
761 type Item = (usize, &'a [T]);
762
763 #[inline]
764 fn next(&mut self) -> Option<Self::Item> {
765 if self.idx >= self.count {
766 return None;
767 }
768 let i = self.idx;
769 self.idx += 1;
770 Some((i, self.fvv.get_slice(i)))
771 }
772
773 fn size_hint(&self) -> (usize, Option<usize>) {
774 let rem = self.count - self.idx;
775 (rem, Some(rem))
776 }
777}
778
779impl<T> ExactSizeIterator for FlatVecVecIter<'_, T> {}
780
781
782#[derive(Debug, Clone, Default, PartialEq)]
803pub struct InheritedValues {
804 buckets: Vec<InheritedBucket>,
805 node_count: usize,
808}
809
810#[derive(Debug, Clone, PartialEq)]
811struct InheritedBucket {
812 prop_type: CssPropertyType,
813 value: CssPropertyWithOrigin,
814 nodes: Vec<u32>,
816}
817
818impl InheritedValues {
819 #[must_use]
820 pub const fn new() -> Self {
821 Self {
822 buckets: Vec::new(),
823 node_count: 0,
824 }
825 }
826
827 #[must_use]
828 pub const fn len(&self) -> usize {
829 self.node_count
830 }
831
832 #[must_use]
833 pub const fn is_empty(&self) -> bool {
834 self.node_count == 0
835 }
836
837 #[must_use]
840 pub fn bucket_count(&self) -> usize {
841 self.buckets.len()
842 }
843
844 #[must_use]
847 pub fn entry_count(&self) -> usize {
848 self.buckets.iter().map(|b| b.nodes.len()).sum()
849 }
850
851 pub fn grow_to(&mut self, node_count: usize) {
852 self.node_count = self.node_count.max(node_count);
853 }
854
855 pub fn clear_values(&mut self) {
857 self.buckets.clear();
858 }
859
860 #[must_use]
864 pub fn get(&self, node: usize, prop_type: CssPropertyType) -> Option<&CssPropertyWithOrigin> {
865 let n = u32::try_from(node).ok()?;
866 self.buckets
867 .iter()
868 .find(|b| b.prop_type == prop_type && b.nodes.binary_search(&n).is_ok())
869 .map(|b| &b.value)
870 }
871
872 #[must_use]
875 pub fn values_for(&self, node: usize) -> Vec<(CssPropertyType, CssPropertyWithOrigin)> {
876 let Ok(n) = u32::try_from(node) else {
877 return Vec::new();
878 };
879 let mut out: Vec<_> = self
880 .buckets
881 .iter()
882 .filter(|b| b.nodes.binary_search(&n).is_ok())
883 .map(|b| (b.prop_type, b.value.clone()))
884 .collect();
885 out.sort_by_key(|(t, _)| *t);
886 out
887 }
888
889 #[must_use]
903 pub fn values_for_opt(
904 &self,
905 node: usize,
906 ) -> Option<Vec<(CssPropertyType, CssPropertyWithOrigin)>> {
907 (node < self.node_count).then(|| self.values_for(node))
908 }
909
910 pub fn set_node(&mut self, node: usize, entries: &[(CssPropertyType, CssPropertyWithOrigin)]) {
915 let Ok(n) = u32::try_from(node) else { return };
916 for (prop_type, value) in entries {
917 match self
918 .buckets
919 .iter_mut()
920 .find(|b| b.prop_type == *prop_type && b.value == *value)
921 {
922 Some(b) => {
923 if b.nodes.last() != Some(&n) {
924 b.nodes.push(n);
925 }
926 }
927 None => self.buckets.push(InheritedBucket {
928 prop_type: *prop_type,
929 value: value.clone(),
930 nodes: vec![n],
931 }),
932 }
933 }
934 }
935
936 pub fn append(&mut self, other: &mut Self) {
939 let shift = u32::try_from(self.node_count).unwrap_or(u32::MAX);
940 for mut ob in core::mem::take(&mut other.buckets) {
941 for n in &mut ob.nodes {
942 *n = n.saturating_add(shift);
943 }
944 match self
945 .buckets
946 .iter_mut()
947 .find(|b| b.prop_type == ob.prop_type && b.value == ob.value)
948 {
949 Some(b) => b.nodes.extend_from_slice(&ob.nodes),
950 None => self.buckets.push(ob),
951 }
952 }
953 self.node_count += other.node_count;
954 other.node_count = 0;
955 }
956
957 #[must_use]
959 pub fn heap_bytes(&self) -> usize {
960 let entry = size_of::<(CssPropertyType, CssPropertyWithOrigin)>();
961 self.buckets.capacity() * size_of::<InheritedBucket>()
962 + self.buckets.len() * entry
963 + self
964 .buckets
965 .iter()
966 .map(|b| b.nodes.capacity() * size_of::<u32>())
967 .sum::<usize>()
968 }
969}
970
971#[derive(Debug, Default, Clone, PartialEq)]
983pub struct CssPropertyCache {
984 pub node_count: usize,
986
987 pub retained_author_css: Css,
994
995 pub user_overridden_properties: Vec<Vec<(CssPropertyType, CssProperty)>>,
997 pub dynamic_context: Option<Box<DynamicSelectorContext>>,
1005
1006 pub cascaded_props: FlatVecVec<StatefulCssProperty>,
1010
1011 pub css_props: FlatVecVec<StatefulCssProperty>,
1014
1015 pub computed_values: InheritedValues,
1023
1024 pub compact_cache: Option<azul_css::compact_cache::CompactLayoutCache>,
1028
1029 pub global_css_props: Vec<CssProperty>,
1033
1034 pub resolved_font_sizes_px: crate::sync::OnceLock<Vec<f32>>,
1048}
1049
1050#[derive(Debug, Clone, Copy, Default)]
1058pub struct CssPropertyCacheBreakdown {
1059 pub node_count: usize,
1060 pub cascaded_props_bytes: usize,
1061 pub css_props_bytes: usize,
1062 pub computed_values_bytes: usize,
1063 pub user_overridden_bytes: usize,
1064 pub global_css_props_bytes: usize,
1065 pub compact_cache_bytes: usize,
1066 pub resolved_font_sizes_bytes: usize,
1067}
1068
1069impl CssPropertyCacheBreakdown {
1070 #[must_use]
1072 pub const fn total_bytes(&self) -> usize {
1073 self.cascaded_props_bytes
1074 + self.css_props_bytes
1075 + self.computed_values_bytes
1076 + self.user_overridden_bytes
1077 + self.global_css_props_bytes
1078 + self.compact_cache_bytes
1079 + self.resolved_font_sizes_bytes
1080 }
1081}
1082
1083impl CssPropertyCache {
1084 pub fn memory_breakdown(&self) -> CssPropertyCacheBreakdown {
1098 let stateful_sz = size_of::<StatefulCssProperty>();
1099 let computed_entry_sz = size_of::<(CssPropertyType, CssPropertyWithOrigin)>();
1100 let outer_vec_sz = size_of::<Vec<(CssPropertyType, CssPropertyWithOrigin)>>();
1101
1102 let cascaded_bytes = self.cascaded_props.heap_bytes(stateful_sz);
1103 let css_bytes = self.css_props.heap_bytes(stateful_sz);
1104
1105 let computed_bytes = self.computed_values.heap_bytes();
1106
1107 let user_overridden_bytes = {
1108 let mut b = self.user_overridden_properties.capacity() * outer_vec_sz;
1109 for v in &self.user_overridden_properties {
1110 b += v.capacity() * size_of::<(CssPropertyType, CssProperty)>();
1111 }
1112 b
1113 };
1114
1115 let global_bytes = self.global_css_props.capacity() * size_of::<CssProperty>();
1116
1117 let compact_bytes = self.compact_cache.as_ref().map_or(0, |c| {
1118 c.tier1_enums.capacity() * 8
1119 + c.tier2_dims.capacity() * 68
1120 + c.tier2_cold.capacity() * 28
1121 + c.tier2b_text.capacity() * 24
1122 + c.prev_font_hashes.capacity() * 8
1123 + c.font_dirty_nodes.capacity() * 8
1124 });
1125
1126 let resolved_font_sizes_bytes = self
1127 .resolved_font_sizes_px
1128 .get()
1129 .map_or(0, |v| v.capacity() * size_of::<f32>());
1130
1131 CssPropertyCacheBreakdown {
1132 node_count: self.node_count,
1133 cascaded_props_bytes: cascaded_bytes,
1134 css_props_bytes: css_bytes,
1135 computed_values_bytes: computed_bytes,
1136 user_overridden_bytes,
1137 global_css_props_bytes: global_bytes,
1138 compact_cache_bytes: compact_bytes,
1139 resolved_font_sizes_bytes,
1140 }
1141 }
1142
1143 pub fn prune_compact_normal_props(&mut self) {
1149 use azul_css::dynamic_selector::PseudoStateType;
1150
1151 #[cfg(feature = "std")]
1152 {
1153 static PRUNE_DBG: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1154 let dbg = *PRUNE_DBG.get_or_init(crate::profile::memory_enabled);
1155 if dbg {
1156 let mut normal_compact = 0usize;
1157 let mut normal_noncompact = 0usize;
1158 let mut nonnormal = 0usize;
1159 for i in 0..self.css_props.len() {
1160 for p in self.css_props.get_slice(i) {
1161 if p.state != PseudoStateType::Normal {
1162 nonnormal += 1;
1163 } else if p.prop_type.has_compact_encoding() {
1164 normal_compact += 1;
1165 } else {
1166 normal_noncompact += 1;
1167 }
1168 }
1169 }
1170 let ssp_sz = size_of::<StatefulCssProperty>();
1171 let mut casc_normal_compact = 0usize;
1172 let mut casc_total = 0usize;
1173 for i in 0..self.cascaded_props.len() {
1174 for p in self.cascaded_props.get_slice(i) {
1175 casc_total += 1;
1176 if p.state == PseudoStateType::Normal && p.prop_type.has_compact_encoding()
1177 {
1178 casc_normal_compact += 1;
1179 }
1180 }
1181 }
1182 eprintln!("[PRUNE] css_props: norm+compact={normal_compact} norm+other={normal_noncompact} nonnorm={nonnormal} SSP={ssp_sz}B | cascaded: total={casc_total} norm+compact={casc_normal_compact}");
1183 }
1184 }
1185
1186 let keep = |p: &StatefulCssProperty| -> bool {
1192 if p.state != PseudoStateType::Normal {
1193 return true;
1194 }
1195 if !p.prop_type.has_compact_encoding() {
1196 return true;
1197 }
1198 if property_needs_slow_path_after_compact(&p.property) {
1201 return true;
1202 }
1203 false
1204 };
1205 if !self.cascaded_props.is_flattened() {
1253 self.cascaded_props
1254 .sort_each_and_flatten(|p| (p.state, p.prop_type));
1255 }
1256 self.cascaded_props.retain(keep);
1257 }
1258
1259 #[inline]
1262 #[allow(clippy::trivially_copy_pass_by_ref)]
1267 fn find_in_stateful<'a>(
1268 props: &'a [StatefulCssProperty],
1269 state: azul_css::dynamic_selector::PseudoStateType,
1270 prop_type: &CssPropertyType,
1271 ) -> Option<&'a CssProperty> {
1272 let key = (state, *prop_type);
1273 props
1274 .binary_search_by_key(&key, |p| (p.state, p.prop_type))
1275 .ok()
1276 .map(|idx| &props[idx].property)
1277 }
1278
1279 #[inline]
1282 fn has_state_props(
1283 props: &[StatefulCssProperty],
1284 state: azul_css::dynamic_selector::PseudoStateType,
1285 ) -> bool {
1286 let i = props.partition_point(|p| p.state < state);
1289 i < props.len() && props[i].state == state
1290 }
1291
1292 pub(crate) fn prop_types_for_state(
1294 props: &[StatefulCssProperty],
1295 state: azul_css::dynamic_selector::PseudoStateType,
1296 ) -> impl Iterator<Item = &CssPropertyType> + '_ {
1297 props
1298 .iter()
1299 .filter(move |p| p.state == state)
1300 .map(|p| &p.prop_type)
1301 }
1302}
1303
1304fn property_needs_slow_path_after_compact(prop: &CssProperty) -> bool {
1314 use azul_css::css::CssPropertyValue;
1315 use azul_css::props::{
1316 basic::length::SizeMetric,
1317 layout::{
1318 dimensions::{LayoutHeight, LayoutWidth},
1319 flex::LayoutFlexBasis,
1320 },
1321 };
1322
1323 macro_rules! check_plain {
1325 ($v:expr) => {{
1326 if let CssPropertyValue::Exact(ref inner) = $v {
1327 return inner.inner.metric != SizeMetric::Px;
1328 }
1329 false
1330 }};
1331 }
1332
1333 match prop {
1334 CssProperty::Width(v) => {
1338 if let CssPropertyValue::Exact(LayoutWidth::Px(pv)) = v {
1339 return pv.metric != SizeMetric::Px;
1340 }
1341 false
1342 }
1343 CssProperty::Height(v) => {
1344 if let CssPropertyValue::Exact(LayoutHeight::Px(pv)) = v {
1345 return pv.metric != SizeMetric::Px;
1346 }
1347 false
1348 }
1349
1350 CssProperty::FlexBasis(v) => {
1352 if let CssPropertyValue::Exact(LayoutFlexBasis::Exact(pv)) = v {
1353 return pv.metric != SizeMetric::Px;
1354 }
1355 false
1356 }
1357
1358 CssProperty::MinWidth(v) => check_plain!(v),
1360 CssProperty::MaxWidth(v) => check_plain!(v),
1361 CssProperty::MinHeight(v) => check_plain!(v),
1362 CssProperty::MaxHeight(v) => check_plain!(v),
1363 CssProperty::FontSize(v) => check_plain!(v),
1364 CssProperty::PaddingTop(v) => check_plain!(v),
1365 CssProperty::PaddingRight(v) => check_plain!(v),
1366 CssProperty::PaddingBottom(v) => check_plain!(v),
1367 CssProperty::PaddingLeft(v) => check_plain!(v),
1368 CssProperty::MarginTop(v) => check_plain!(v),
1369 CssProperty::MarginRight(v) => check_plain!(v),
1370 CssProperty::MarginBottom(v) => check_plain!(v),
1371 CssProperty::MarginLeft(v) => check_plain!(v),
1372 CssProperty::BorderTopWidth(v) => check_plain!(v),
1373 CssProperty::BorderRightWidth(v) => check_plain!(v),
1374 CssProperty::BorderBottomWidth(v) => check_plain!(v),
1375 CssProperty::BorderLeftWidth(v) => check_plain!(v),
1376 CssProperty::Top(v) => check_plain!(v),
1377 CssProperty::Right(v) => check_plain!(v),
1378 CssProperty::Bottom(v) => check_plain!(v),
1379 CssProperty::Left(v) => check_plain!(v),
1380 CssProperty::ColumnGap(v) => check_plain!(v),
1381 CssProperty::RowGap(v) => check_plain!(v),
1382 CssProperty::LetterSpacing(v) => check_plain!(v),
1383 CssProperty::WordSpacing(v) => check_plain!(v),
1384 CssProperty::TextIndent(v) => check_plain!(v),
1385 CssProperty::TabSize(v) => check_plain!(v),
1386
1387 _ => false,
1389 }
1390}
1391
1392fn is_resolved_parent_inherited(prop_type: CssPropertyType) -> bool {
1417 prop_type == CssPropertyType::FontSize
1418}
1419
1420fn clone_inheritable_property(p: &CssProperty) -> CssProperty {
1421 use azul_css::props::property::CssProperty;
1422 if let CssProperty::FontFamily(v) = p {
1423 return CssProperty::FontFamily(v.clone());
1424 }
1425 if let CssProperty::BackgroundContent(v) = p {
1426 return CssProperty::BackgroundContent(v.clone());
1427 }
1428 if let CssProperty::BackgroundPosition(v) = p {
1429 return CssProperty::BackgroundPosition(v.clone());
1430 }
1431 if let CssProperty::BackgroundSize(v) = p {
1432 return CssProperty::BackgroundSize(v.clone());
1433 }
1434 if let CssProperty::BackgroundRepeat(v) = p {
1435 return CssProperty::BackgroundRepeat(v.clone());
1436 }
1437 if let CssProperty::BoxShadowLeft(v) = p {
1438 return CssProperty::BoxShadowLeft(v.clone());
1439 }
1440 if let CssProperty::BoxShadowRight(v) = p {
1441 return CssProperty::BoxShadowRight(v.clone());
1442 }
1443 if let CssProperty::BoxShadowTop(v) = p {
1444 return CssProperty::BoxShadowTop(v.clone());
1445 }
1446 if let CssProperty::BoxShadowBottom(v) = p {
1447 return CssProperty::BoxShadowBottom(v.clone());
1448 }
1449 if let CssProperty::TextShadow(v) = p {
1450 return CssProperty::TextShadow(v.clone());
1451 }
1452 if let CssProperty::ScrollbarTrack(v) = p {
1453 return CssProperty::ScrollbarTrack(v.clone());
1454 }
1455 if let CssProperty::ScrollbarThumb(v) = p {
1456 return CssProperty::ScrollbarThumb(v.clone());
1457 }
1458 if let CssProperty::ScrollbarButton(v) = p {
1459 return CssProperty::ScrollbarButton(v.clone());
1460 }
1461 if let CssProperty::ScrollbarCorner(v) = p {
1462 return CssProperty::ScrollbarCorner(v.clone());
1463 }
1464 if let CssProperty::ScrollbarResizer(v) = p {
1465 return CssProperty::ScrollbarResizer(v.clone());
1466 }
1467 if let CssProperty::Transform(v) = p {
1468 return CssProperty::Transform(v.clone());
1469 }
1470 if let CssProperty::Filter(v) = p {
1471 return CssProperty::Filter(v.clone());
1472 }
1473 if let CssProperty::BackdropFilter(v) = p {
1474 return CssProperty::BackdropFilter(v.clone());
1475 }
1476 if let CssProperty::Content(v) = p {
1477 return CssProperty::Content(v.clone());
1478 }
1479 if let CssProperty::HyphenationLanguage(v) = p {
1480 return CssProperty::HyphenationLanguage(v.clone());
1481 }
1482 if let CssProperty::Cursor(v) = p {
1483 return CssProperty::Cursor(*v);
1484 }
1485 p.clone()
1486}
1487
1488impl CssPropertyCache {
1489 #[must_use]
1493 #[allow(clippy::too_many_lines, clippy::cognitive_complexity)] pub fn restyle(
1495 &mut self,
1496 css: &mut Css,
1497 node_data: &NodeDataContainerRef<'_, NodeData>,
1498 node_hierarchy: &NodeHierarchyItemVec,
1499 non_leaf_nodes: &ParentWithNodeDepthVec,
1500 html_tree: &NodeDataContainerRef<'_, CascadeInfo>,
1501 ) -> Vec<TagIdToNodeIdMapping> {
1502 use azul_css::{
1503 css::{
1504 CssPathPseudoSelector::{Active, DragOver, Dragging, Focus, Hover, Placeholder, SeatFocus},
1505 CssPathSelector, CssRuleBlock,
1506 },
1507 dynamic_selector::{DynamicSelector, PseudoStateType},
1508 props::layout::LayoutDisplay,
1509 };
1510
1511 let css_is_empty = css.is_empty();
1512
1513 let dyn_ctx = self.dynamic_context.clone();
1524 let rule_applies = |conds: &azul_css::dynamic_selector::DynamicSelectorVec| -> bool {
1525 let cs = conds.as_slice();
1526 cs.is_empty()
1527 || dyn_ctx
1528 .as_deref()
1529 .is_some_and(|c| cs.iter().all(|sel| sel.matches(c)))
1530 };
1531
1532 if !css_is_empty {
1533 css.sort_by_specificity();
1534
1535 let mut global_only_rules: Vec<&CssRuleBlock> = Vec::new();
1540 let mut specific_rules: Vec<&CssRuleBlock> = Vec::new();
1541
1542 for rule in css.rules() {
1543 let selectors = rule.path.selectors.as_ref();
1544 let is_global_only = selectors.len() == 1
1545 && matches!(selectors.first(), Some(CssPathSelector::Global));
1546 if is_global_only {
1547 global_only_rules.push(rule);
1548 } else {
1549 specific_rules.push(rule);
1550 }
1551 }
1552
1553 let node_count = self.css_props.len();
1575 self.css_props = FlatVecVec::new(node_count);
1576 self.cascaded_props = FlatVecVec::new(node_count);
1577
1578 self.global_css_props.clear();
1583 for rule in &global_only_rules {
1584 if !rule_applies(&rule.conditions) {
1585 continue;
1586 }
1587 if crate::style::rule_ends_with(&rule.path, None) {
1588 for d in &rule.declarations {
1589 if let Some(s) = d.resolve_in_cascade(dyn_ctx.as_deref()) {
1592 self.global_css_props.push(s);
1593 }
1594 }
1595 }
1596 }
1597
1598 if !specific_rules.is_empty() {
1600 macro_rules! filter_rules {
1610 ($expected_pseudo_selector:expr, $node_id:expr) => {{
1611 let mut out: Vec<(u16, u16)> = Vec::new();
1612 for (rule_idx, rule_block) in specific_rules.iter().enumerate() {
1613 if !rule_applies(&rule_block.conditions) {
1614 continue;
1615 }
1616 if !crate::style::rule_ends_with(
1617 &rule_block.path,
1618 $expected_pseudo_selector,
1619 ) {
1620 continue;
1621 }
1622 if !crate::style::matches_html_element(
1623 &rule_block.path,
1624 $node_id,
1625 &node_hierarchy.as_container(),
1626 &node_data,
1627 &html_tree,
1628 $expected_pseudo_selector,
1629 ) {
1630 continue;
1631 }
1632 for (decl_idx, decl) in
1633 rule_block.declarations.as_slice().iter().enumerate()
1634 {
1635 if decl.is_cascade_resolvable() {
1636 out.push((
1637 u16::try_from(rule_idx).unwrap_or(u16::MAX),
1638 u16::try_from(decl_idx).unwrap_or(u16::MAX),
1639 ));
1640 }
1641 }
1642 }
1643 out
1644 }};
1645 }
1646
1647 let has_normal = specific_rules
1651 .iter()
1652 .any(|r| crate::style::rule_ends_with(&r.path, None));
1653 let has_hover = specific_rules
1654 .iter()
1655 .any(|r| crate::style::rule_ends_with(&r.path, Some(Hover)));
1656 let has_active = specific_rules
1657 .iter()
1658 .any(|r| crate::style::rule_ends_with(&r.path, Some(Active)));
1659 let has_focus = specific_rules
1660 .iter()
1661 .any(|r| crate::style::rule_ends_with(&r.path, Some(Focus)));
1662 let has_seat_focus = specific_rules
1663 .iter()
1664 .any(|r| crate::style::rule_ends_with(&r.path, Some(SeatFocus)));
1665 let has_dragging = specific_rules
1666 .iter()
1667 .any(|r| crate::style::rule_ends_with(&r.path, Some(Dragging)));
1668 let has_drag_over = specific_rules
1669 .iter()
1670 .any(|r| crate::style::rule_ends_with(&r.path, Some(DragOver)));
1671 let has_placeholder = specific_rules
1672 .iter()
1673 .any(|r| crate::style::rule_ends_with(&r.path, Some(Placeholder)));
1674
1675 macro_rules! collect_and_assign {
1676 ($pseudo:expr, $state:expr, $has_any:expr) => {
1677 if $has_any {
1678 let indices: NodeDataContainer<(NodeId, Vec<(u16, u16)>)> = node_data
1679 .transform_nodeid_optional(|node_id| {
1680 let r = filter_rules!($pseudo, node_id);
1681 if r.is_empty() {
1682 None
1683 } else {
1684 Some((node_id, r))
1685 }
1686 });
1687 for (n, pairs) in indices.internal.into_iter() {
1688 for (rule_idx, decl_idx) in pairs {
1689 let decl = &specific_rules[rule_idx as usize]
1690 .declarations
1691 .as_slice()[decl_idx as usize];
1692 if let Some(prop) = decl.resolve_in_cascade(dyn_ctx.as_deref())
1693 {
1694 self.css_props.push_to(
1695 n.index(),
1696 StatefulCssProperty {
1697 state: $state,
1698 prop_type: prop.get_type(),
1699 property: prop,
1700 },
1701 );
1702 }
1703 }
1704 }
1705 }
1706 };
1707 }
1708
1709 collect_and_assign!(None, PseudoStateType::Normal, has_normal);
1710 collect_and_assign!(Some(Hover), PseudoStateType::Hover, has_hover);
1711 collect_and_assign!(Some(Active), PseudoStateType::Active, has_active);
1712 collect_and_assign!(Some(Focus), PseudoStateType::Focus, has_focus);
1713 collect_and_assign!(
1714 Some(SeatFocus),
1715 PseudoStateType::SeatFocus,
1716 has_seat_focus
1717 );
1718 collect_and_assign!(Some(Dragging), PseudoStateType::Dragging, has_dragging);
1719 collect_and_assign!(Some(DragOver), PseudoStateType::DragOver, has_drag_over);
1720 collect_and_assign!(
1721 Some(Placeholder),
1722 PseudoStateType::Placeholder,
1723 has_placeholder
1724 );
1725 } }
1727
1728 for ParentWithNodeDepth { depth: _, node_id } in non_leaf_nodes {
1731 let Some(parent_id) = node_id.into_crate_internal() else {
1732 continue;
1733 };
1734
1735 let all_states = [
1736 PseudoStateType::Normal,
1737 PseudoStateType::Hover,
1738 PseudoStateType::Active,
1739 PseudoStateType::Focus,
1740 PseudoStateType::SeatFocus,
1741 PseudoStateType::Dragging,
1742 PseudoStateType::DragOver,
1743 PseudoStateType::Placeholder,
1744 ];
1745
1746 for &state in &all_states {
1747 let parent_inheritable_inline: Vec<(CssPropertyType, CssProperty)> = node_data
1749 [parent_id]
1750 .style
1751 .iter_inline_properties()
1752 .filter(|(_prop, conds)| {
1753 let conditions = conds.as_slice();
1754 if conditions.is_empty() {
1755 state == PseudoStateType::Normal
1756 } else {
1757 conditions.iter().all(
1758 |c| matches!(c, DynamicSelector::PseudoState(s) if *s == state),
1759 )
1760 }
1761 })
1762 .map(|(prop, _)| prop)
1763 .filter(|prop| {
1764 prop.get_type().is_inheritable()
1765 && !is_resolved_parent_inherited(prop.get_type())
1766 })
1767 .map(|p| (p.get_type(), clone_inheritable_property(p)))
1768 .collect();
1769
1770 let parent_inheritable_css: Vec<(CssPropertyType, CssProperty)> = if css_is_empty {
1772 Vec::new()
1773 } else {
1774 self.css_props
1775 .get_slice(parent_id.index())
1776 .iter()
1777 .filter(|p| {
1778 p.state == state
1779 && p.prop_type.is_inheritable()
1780 && !is_resolved_parent_inherited(p.prop_type)
1781 })
1782 .map(|p| (p.prop_type, clone_inheritable_property(&p.property)))
1783 .collect()
1784 };
1785
1786 let parent_inheritable_cascaded: Vec<(CssPropertyType, CssProperty)> = self
1788 .cascaded_props
1789 .get_slice(parent_id.index())
1790 .iter()
1791 .filter(|p| {
1792 p.state == state
1793 && p.prop_type.is_inheritable()
1794 && !is_resolved_parent_inherited(p.prop_type)
1795 })
1796 .map(|p| (p.prop_type, clone_inheritable_property(&p.property)))
1797 .collect();
1798
1799 if parent_inheritable_inline.is_empty()
1802 && parent_inheritable_css.is_empty()
1803 && parent_inheritable_cascaded.is_empty()
1804 {
1805 continue;
1806 }
1807
1808 for child_id in parent_id.az_children(&node_hierarchy.as_container()) {
1809 let child_vec = self.cascaded_props.build_mut(child_id.index());
1810 for (prop_type, prop_value) in parent_inheritable_inline
1811 .iter()
1812 .chain(parent_inheritable_css.iter())
1813 .chain(parent_inheritable_cascaded.iter())
1814 {
1815 if !child_vec
1817 .iter()
1818 .any(|p| p.state == state && p.prop_type == *prop_type)
1819 {
1820 child_vec.push(StatefulCssProperty {
1821 state,
1822 prop_type: *prop_type,
1823 property: prop_value.clone(),
1824 });
1825 }
1826 }
1827 }
1828 }
1829 }
1830
1831 self.css_props
1834 .sort_each_and_flatten(|p| (p.state, p.prop_type));
1835
1836 self.invalidate_resolved_font_sizes();
1839
1840 self.generate_tag_ids(node_data, node_hierarchy)
1841 }
1842
1843 #[allow(clippy::too_many_lines)] pub fn generate_tag_ids(
1848 &self,
1849 node_data: &NodeDataContainerRef<'_, NodeData>,
1850 node_hierarchy: &NodeHierarchyItemVec,
1851 ) -> Vec<TagIdToNodeIdMapping> {
1852 use azul_css::compact_cache::{
1856 DISPLAY_MASK, DISPLAY_SHIFT, OVERFLOW_MASK, OVERFLOW_X_SHIFT, OVERFLOW_Y_SHIFT,
1857 };
1858
1859 let compact_cache = self.compact_cache.as_ref();
1860 let node_data_container = &node_data.internal;
1861
1862 let tag_ids = node_data
1863 .internal
1864 .iter()
1865 .enumerate()
1866 .filter_map(|(node_idx, node_data)| {
1867 let node_id = NodeId::new(node_idx);
1868
1869 let should_auto_insert_tabindex = node_data
1870 .get_callbacks()
1871 .iter()
1872 .any(|cb| cb.event.is_focus_callback());
1873
1874 let tab_index = node_data.get_tab_index().map_or(
1875 if should_auto_insert_tabindex {
1876 Some(TabIndex::Auto)
1877 } else {
1878 None
1879 },
1880 Some,
1881 );
1882
1883 let mut need_tag = false;
1884
1885 'compute_need_tag: {
1889 if let Some(cc) = compact_cache.as_ref() {
1891 let t1 = cc.tier1_enums[node_idx];
1892 let display_val = ((t1 >> DISPLAY_SHIFT) & DISPLAY_MASK) as u8;
1893 if display_val == 4 {
1894 break 'compute_need_tag;
1895 } }
1897
1898 if node_data.has_context_menu() || node_data.get_context_menu().is_some() {
1899 need_tag = true;
1900 break 'compute_need_tag;
1901 }
1902 if tab_index.is_some() {
1903 need_tag = true;
1904 break 'compute_need_tag;
1905 }
1906
1907 {
1909 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
1910 let has_pseudo = |state: PseudoStateType| -> bool {
1911 node_data.style.iter_inline_properties().any(|(_p, conds)| {
1912 conds.as_slice().iter().any(
1913 |c| matches!(c, DynamicSelector::PseudoState(s) if *s == state),
1914 )
1915 }) || Self::has_state_props(self.css_props.get_slice(node_idx), state)
1916 };
1917
1918 if has_pseudo(PseudoStateType::Hover)
1919 || has_pseudo(PseudoStateType::Active)
1920 || has_pseudo(PseudoStateType::Focus)
1921 || has_pseudo(PseudoStateType::SeatFocus)
1922 || has_pseudo(PseudoStateType::Dragging)
1923 || has_pseudo(PseudoStateType::DragOver)
1924 {
1925 need_tag = true;
1926 break 'compute_need_tag;
1927 }
1928 }
1929
1930 let has_non_window_cb = !node_data.get_callbacks().is_empty()
1932 && !node_data
1933 .get_callbacks()
1934 .iter()
1935 .all(|cb| cb.event.is_window_callback());
1936 if has_non_window_cb {
1937 need_tag = true;
1938 break 'compute_need_tag;
1939 }
1940
1941 if self.css_props.get_slice(node_idx).iter().any(|p| {
1943 p.state == azul_css::dynamic_selector::PseudoStateType::Normal
1944 && p.prop_type == CssPropertyType::Cursor
1945 }) || node_data
1946 .style
1947 .iter_inline_properties()
1948 .any(|(p, _)| p.get_type() == CssPropertyType::Cursor)
1949 {
1950 need_tag = true;
1951 break 'compute_need_tag;
1952 }
1953
1954 if let Some(cc) = compact_cache.as_ref() {
1956 let t1 = cc.tier1_enums[node_idx];
1957 let ox = ((t1 >> OVERFLOW_X_SHIFT) & OVERFLOW_MASK) as u8;
1958 let oy = ((t1 >> OVERFLOW_Y_SHIFT) & OVERFLOW_MASK) as u8;
1959 if ox == 2 || ox == 3 || oy == 2 || oy == 3 {
1961 need_tag = true;
1962 break 'compute_need_tag;
1963 }
1964 }
1965
1966 {
1968 use crate::dom::NodeType;
1969 let hier = node_hierarchy.as_container()[node_id];
1970 let mut has_text = false;
1971 if let Some(first_child) = hier.first_child_id(node_id) {
1972 let mut child_id = Some(first_child);
1973 while let Some(cid) = child_id {
1974 if matches!(
1975 node_data_container[cid.index()].get_node_type(),
1976 NodeType::Text(_)
1977 ) {
1978 has_text = true;
1979 break;
1980 }
1981 child_id = node_hierarchy.as_container()[cid].next_sibling_id();
1982 }
1983 }
1984 if has_text {
1985 need_tag = true;
1986 break 'compute_need_tag;
1987 }
1988 }
1989
1990 break 'compute_need_tag;
1991 }
1992
1993 if need_tag {
1994 Some(TagIdToNodeIdMapping {
2017 tag_id: TagId::from_crate_internal(TagId {
2018 inner: (node_idx as u64) + 1,
2019 }),
2020 node_id: NodeHierarchyItemId::from_crate_internal(Some(node_id)),
2021 tab_index: tab_index.into(),
2022 })
2023 } else {
2024 None
2025 }
2026 })
2027 .collect::<Vec<_>>();
2028
2029 tag_ids
2030 }
2031
2032 #[allow(clippy::too_many_lines, clippy::cognitive_complexity)] pub fn get_computed_css_style_string(
2034 &self,
2035 node_data: &NodeData,
2036 node_id: &NodeId,
2037 node_state: &StyledNodeState,
2038 ) -> String {
2039 let mut s = String::new();
2040 if let Some(p) = self.get_background_content(node_data, node_id, node_state) {
2041 let _ = write!(s, "background: {};", p.get_css_value_fmt());
2042 }
2043 if let Some(p) = self.get_background_position(node_data, node_id, node_state) {
2044 let _ = write!(s, "background-position: {};", p.get_css_value_fmt());
2045 }
2046 if let Some(p) = self.get_background_size(node_data, node_id, node_state) {
2047 let _ = write!(s, "background-size: {};", p.get_css_value_fmt());
2048 }
2049 if let Some(p) = self.get_background_repeat(node_data, node_id, node_state) {
2050 let _ = write!(s, "background-repeat: {};", p.get_css_value_fmt());
2051 }
2052 if let Some(p) = self.get_font_size(node_data, node_id, node_state) {
2053 let _ = write!(s, "font-size: {};", p.get_css_value_fmt());
2054 }
2055 if let Some(p) = self.get_font_family(node_data, node_id, node_state) {
2056 let _ = write!(s, "font-family: {};", p.get_css_value_fmt());
2057 }
2058 if let Some(p) = self.get_text_color(node_data, node_id, node_state) {
2059 let _ = write!(s, "color: {};", p.get_css_value_fmt());
2060 }
2061 if let Some(p) = self.get_text_align(node_data, node_id, node_state) {
2062 let _ = write!(s, "text-align: {};", p.get_css_value_fmt());
2063 }
2064 if let Some(p) = self.get_line_height(node_data, node_id, node_state) {
2065 let _ = write!(s, "line-height: {};", p.get_css_value_fmt());
2066 }
2067 if let Some(p) = self.get_letter_spacing(node_data, node_id, node_state) {
2068 let _ = write!(s, "letter-spacing: {};", p.get_css_value_fmt());
2069 }
2070 if let Some(p) = self.get_word_spacing(node_data, node_id, node_state) {
2071 let _ = write!(s, "word-spacing: {};", p.get_css_value_fmt());
2072 }
2073 if let Some(p) = self.get_tab_size(node_data, node_id, node_state) {
2074 let _ = write!(s, "tab-size: {};", p.get_css_value_fmt());
2075 }
2076 if let Some(p) = self.get_cursor(node_data, node_id, node_state) {
2077 let _ = write!(s, "cursor: {};", p.get_css_value_fmt());
2078 }
2079 if let Some(p) = self.get_box_shadow_left(node_data, node_id, node_state) {
2080 let _ = write!(s, "-azul-box-shadow-left: {};", p.get_css_value_fmt());
2081 }
2082 if let Some(p) = self.get_box_shadow_right(node_data, node_id, node_state) {
2083 let _ = write!(s, "-azul-box-shadow-right: {};", p.get_css_value_fmt());
2084 }
2085 if let Some(p) = self.get_box_shadow_top(node_data, node_id, node_state) {
2086 let _ = write!(s, "-azul-box-shadow-top: {};", p.get_css_value_fmt());
2087 }
2088 if let Some(p) = self.get_box_shadow_bottom(node_data, node_id, node_state) {
2089 let _ = write!(s, "-azul-box-shadow-bottom: {};", p.get_css_value_fmt());
2090 }
2091 if let Some(p) = self.get_border_top_color(node_data, node_id, node_state) {
2092 let _ = write!(s, "border-top-color: {};", p.get_css_value_fmt());
2093 }
2094 if let Some(p) = self.get_border_left_color(node_data, node_id, node_state) {
2095 let _ = write!(s, "border-left-color: {};", p.get_css_value_fmt());
2096 }
2097 if let Some(p) = self.get_border_right_color(node_data, node_id, node_state) {
2098 let _ = write!(s, "border-right-color: {};", p.get_css_value_fmt());
2099 }
2100 if let Some(p) = self.get_border_bottom_color(node_data, node_id, node_state) {
2101 let _ = write!(s, "border-bottom-color: {};", p.get_css_value_fmt());
2102 }
2103 if let Some(p) = self.get_border_top_style(node_data, node_id, node_state) {
2104 let _ = write!(s, "border-top-style: {};", p.get_css_value_fmt());
2105 }
2106 if let Some(p) = self.get_border_left_style(node_data, node_id, node_state) {
2107 let _ = write!(s, "border-left-style: {};", p.get_css_value_fmt());
2108 }
2109 if let Some(p) = self.get_border_right_style(node_data, node_id, node_state) {
2110 let _ = write!(s, "border-right-style: {};", p.get_css_value_fmt());
2111 }
2112 if let Some(p) = self.get_border_bottom_style(node_data, node_id, node_state) {
2113 let _ = write!(s, "border-bottom-style: {};", p.get_css_value_fmt());
2114 }
2115 if let Some(p) = self.get_border_top_left_radius(node_data, node_id, node_state) {
2116 let _ = write!(s, "border-top-left-radius: {};", p.get_css_value_fmt());
2117 }
2118 if let Some(p) = self.get_border_top_right_radius(node_data, node_id, node_state) {
2119 let _ = write!(s, "border-top-right-radius: {};", p.get_css_value_fmt());
2120 }
2121 if let Some(p) = self.get_border_bottom_left_radius(node_data, node_id, node_state) {
2122 let _ = write!(s, "border-bottom-left-radius: {};", p.get_css_value_fmt());
2123 }
2124 if let Some(p) = self.get_border_bottom_right_radius(node_data, node_id, node_state) {
2125 let _ = write!(s, "border-bottom-right-radius: {};", p.get_css_value_fmt());
2126 }
2127 if let Some(p) = self.get_opacity(node_data, node_id, node_state) {
2128 let _ = write!(s, "opacity: {};", p.get_css_value_fmt());
2129 }
2130 if let Some(p) = self.get_transform(node_data, node_id, node_state) {
2131 let _ = write!(s, "transform: {};", p.get_css_value_fmt());
2132 }
2133 if let Some(p) = self.get_transform_origin(node_data, node_id, node_state) {
2134 let _ = write!(s, "transform-origin: {};", p.get_css_value_fmt());
2135 }
2136 if let Some(p) = self.get_perspective_origin(node_data, node_id, node_state) {
2137 let _ = write!(s, "perspective-origin: {};", p.get_css_value_fmt());
2138 }
2139 if let Some(p) = self.get_backface_visibility(node_data, node_id, node_state) {
2140 let _ = write!(s, "backface-visibility: {};", p.get_css_value_fmt());
2141 }
2142 if let Some(p) = self.get_hyphens(node_data, node_id, node_state) {
2143 let _ = write!(s, "hyphens: {};", p.get_css_value_fmt());
2144 }
2145 if let Some(p) = self.get_direction(node_data, node_id, node_state) {
2146 let _ = write!(s, "direction: {};", p.get_css_value_fmt());
2147 }
2148 if let Some(p) = self.get_unicode_bidi(node_data, node_id, node_state) {
2149 let _ = write!(s, "unicode-bidi: {};", p.get_css_value_fmt());
2150 }
2151 if let Some(p) = self.get_text_box_trim(node_data, node_id, node_state) {
2152 let _ = write!(s, "text-box-trim: {};", p.get_css_value_fmt());
2153 }
2154 if let Some(p) = self.get_text_box_edge(node_data, node_id, node_state) {
2155 let _ = write!(s, "text-box-edge: {};", p.get_css_value_fmt());
2156 }
2157 if let Some(p) = self.get_dominant_baseline(node_data, node_id, node_state) {
2158 let _ = write!(s, "dominant-baseline: {};", p.get_css_value_fmt());
2159 }
2160 if let Some(p) = self.get_alignment_baseline(node_data, node_id, node_state) {
2161 let _ = write!(s, "alignment-baseline: {};", p.get_css_value_fmt());
2162 }
2163 if let Some(p) = self.get_baseline_source(node_data, node_id, node_state) {
2164 let _ = write!(s, "baseline-source: {};", p.get_css_value_fmt());
2165 }
2166 if let Some(p) = self.get_line_fit_edge(node_data, node_id, node_state) {
2167 let _ = write!(s, "line-fit-edge: {};", p.get_css_value_fmt());
2168 }
2169 if let Some(p) = self.get_initial_letter_align(node_data, node_id, node_state) {
2170 let _ = write!(s, "initial-letter-align: {};", p.get_css_value_fmt());
2171 }
2172 if let Some(p) = self.get_initial_letter_wrap(node_data, node_id, node_state) {
2173 let _ = write!(s, "initial-letter-wrap: {};", p.get_css_value_fmt());
2174 }
2175 if let Some(p) = self.get_scrollbar_gutter(node_data, node_id, node_state) {
2176 let _ = write!(s, "scrollbar-gutter: {};", p.get_css_value_fmt());
2177 }
2178 if let Some(p) = self.get_overflow_clip_margin(node_data, node_id, node_state) {
2179 let _ = write!(s, "overflow-clip-margin: {};", p.get_css_value_fmt());
2180 }
2181 if let Some(p) = self.get_clip(node_data, node_id, node_state) {
2182 let _ = write!(s, "clip: {};", p.get_css_value_fmt());
2183 }
2184 if let Some(p) = self.get_white_space(node_data, node_id, node_state) {
2185 let _ = write!(s, "white-space: {};", p.get_css_value_fmt());
2186 }
2187 if let Some(p) = self.get_display(node_data, node_id, node_state) {
2188 let _ = write!(s, "display: {};", p.get_css_value_fmt());
2189 }
2190 if let Some(p) = self.get_float(node_data, node_id, node_state) {
2191 let _ = write!(s, "float: {};", p.get_css_value_fmt());
2192 }
2193 if let Some(p) = self.get_box_sizing(node_data, node_id, node_state) {
2194 let _ = write!(s, "box-sizing: {};", p.get_css_value_fmt());
2195 }
2196 if let Some(p) = self.get_width(node_data, node_id, node_state) {
2197 let _ = write!(s, "width: {};", p.get_css_value_fmt());
2198 }
2199 if let Some(p) = self.get_height(node_data, node_id, node_state) {
2200 let _ = write!(s, "height: {};", p.get_css_value_fmt());
2201 }
2202 if let Some(p) = self.get_min_width(node_data, node_id, node_state) {
2203 let _ = write!(s, "min-width: {};", p.get_css_value_fmt());
2204 }
2205 if let Some(p) = self.get_min_height(node_data, node_id, node_state) {
2206 let _ = write!(s, "min-height: {};", p.get_css_value_fmt());
2207 }
2208 if let Some(p) = self.get_max_width(node_data, node_id, node_state) {
2209 let _ = write!(s, "max-width: {};", p.get_css_value_fmt());
2210 }
2211 if let Some(p) = self.get_max_height(node_data, node_id, node_state) {
2212 let _ = write!(s, "max-height: {};", p.get_css_value_fmt());
2213 }
2214 if let Some(p) = self.get_position(node_data, node_id, node_state) {
2215 let _ = write!(s, "position: {};", p.get_css_value_fmt());
2216 }
2217 if let Some(p) = self.get_top(node_data, node_id, node_state) {
2218 let _ = write!(s, "top: {};", p.get_css_value_fmt());
2219 }
2220 if let Some(p) = self.get_bottom(node_data, node_id, node_state) {
2221 let _ = write!(s, "bottom: {};", p.get_css_value_fmt());
2222 }
2223 if let Some(p) = self.get_right(node_data, node_id, node_state) {
2224 let _ = write!(s, "right: {};", p.get_css_value_fmt());
2225 }
2226 if let Some(p) = self.get_left(node_data, node_id, node_state) {
2227 let _ = write!(s, "left: {};", p.get_css_value_fmt());
2228 }
2229 if let Some(p) = self.get_padding_top(node_data, node_id, node_state) {
2230 let _ = write!(s, "padding-top: {};", p.get_css_value_fmt());
2231 }
2232 if let Some(p) = self.get_padding_bottom(node_data, node_id, node_state) {
2233 let _ = write!(s, "padding-bottom: {};", p.get_css_value_fmt());
2234 }
2235 if let Some(p) = self.get_padding_left(node_data, node_id, node_state) {
2236 let _ = write!(s, "padding-left: {};", p.get_css_value_fmt());
2237 }
2238 if let Some(p) = self.get_padding_right(node_data, node_id, node_state) {
2239 let _ = write!(s, "padding-right: {};", p.get_css_value_fmt());
2240 }
2241 if let Some(p) = self.get_margin_top(node_data, node_id, node_state) {
2242 let _ = write!(s, "margin-top: {};", p.get_css_value_fmt());
2243 }
2244 if let Some(p) = self.get_margin_bottom(node_data, node_id, node_state) {
2245 let _ = write!(s, "margin-bottom: {};", p.get_css_value_fmt());
2246 }
2247 if let Some(p) = self.get_margin_left(node_data, node_id, node_state) {
2248 let _ = write!(s, "margin-left: {};", p.get_css_value_fmt());
2249 }
2250 if let Some(p) = self.get_margin_right(node_data, node_id, node_state) {
2251 let _ = write!(s, "margin-right: {};", p.get_css_value_fmt());
2252 }
2253 if let Some(p) = self.get_border_top_width(node_data, node_id, node_state) {
2254 let _ = write!(s, "border-top-width: {};", p.get_css_value_fmt());
2255 }
2256 if let Some(p) = self.get_border_left_width(node_data, node_id, node_state) {
2257 let _ = write!(s, "border-left-width: {};", p.get_css_value_fmt());
2258 }
2259 if let Some(p) = self.get_border_right_width(node_data, node_id, node_state) {
2260 let _ = write!(s, "border-right-width: {};", p.get_css_value_fmt());
2261 }
2262 if let Some(p) = self.get_border_bottom_width(node_data, node_id, node_state) {
2263 let _ = write!(s, "border-bottom-width: {};", p.get_css_value_fmt());
2264 }
2265 if let Some(p) = self.get_overflow_x(node_data, node_id, node_state) {
2266 let _ = write!(s, "overflow-x: {};", p.get_css_value_fmt());
2267 }
2268 if let Some(p) = self.get_overflow_y(node_data, node_id, node_state) {
2269 let _ = write!(s, "overflow-y: {};", p.get_css_value_fmt());
2270 }
2271 if let Some(p) = self.get_flex_direction(node_data, node_id, node_state) {
2272 let _ = write!(s, "flex-direction: {};", p.get_css_value_fmt());
2273 }
2274 if let Some(p) = self.get_flex_wrap(node_data, node_id, node_state) {
2275 let _ = write!(s, "flex-wrap: {};", p.get_css_value_fmt());
2276 }
2277 if let Some(p) = self.get_flex_grow(node_data, node_id, node_state) {
2278 let _ = write!(s, "flex-grow: {};", p.get_css_value_fmt());
2279 }
2280 if let Some(p) = self.get_flex_shrink(node_data, node_id, node_state) {
2281 let _ = write!(s, "flex-shrink: {};", p.get_css_value_fmt());
2282 }
2283 if let Some(p) = self.get_justify_content(node_data, node_id, node_state) {
2284 let _ = write!(s, "justify-content: {};", p.get_css_value_fmt());
2285 }
2286 if let Some(p) = self.get_align_items(node_data, node_id, node_state) {
2287 let _ = write!(s, "align-items: {};", p.get_css_value_fmt());
2288 }
2289 if let Some(p) = self.get_align_content(node_data, node_id, node_state) {
2290 let _ = write!(s, "align-content: {};", p.get_css_value_fmt());
2291 }
2292 s
2293 }
2294}
2295
2296#[repr(C)]
2297#[derive(Debug, PartialEq, Clone)]
2298pub struct CssPropertyCachePtr {
2299 pub ptr: ManuallyDrop<Box<CssPropertyCache>>,
2307 pub run_destructor: bool,
2308}
2309
2310impl CssPropertyCachePtr {
2311 pub fn new(cache: CssPropertyCache) -> Self {
2312 Self {
2313 ptr: ManuallyDrop::new(Box::new(cache)),
2314 run_destructor: true,
2315 }
2316 }
2317 pub fn downcast_mut(&mut self) -> &mut CssPropertyCache {
2318 &mut self.ptr
2319 }
2320}
2321
2322impl Drop for CssPropertyCachePtr {
2323 fn drop(&mut self) {
2324 if self.run_destructor {
2327 self.run_destructor = false;
2328 unsafe {
2329 ManuallyDrop::drop(&mut self.ptr);
2330 }
2331 }
2332 }
2333}
2334
2335macro_rules! impl_get_prop {
2339 ($name:ident, $value_ty:ty, $variant:ident, $as_method:ident) => {
2340 pub fn $name<'a>(
2341 &'a self,
2342 node_data: &'a NodeData,
2343 node_id: &NodeId,
2344 node_state: &StyledNodeState,
2345 ) -> Option<&'a $value_ty> {
2346 self.get_property(node_data, node_id, node_state, &CssPropertyType::$variant)
2347 .and_then(|p| p.$as_method())
2348 }
2349 };
2350}
2351
2352impl CssPropertyCache {
2353 #[must_use]
2354 pub fn empty(node_count: usize) -> Self {
2355 Self {
2356 node_count,
2357 retained_author_css: Css::default(),
2358 user_overridden_properties: Vec::new(),
2359 dynamic_context: None,
2360
2361 cascaded_props: FlatVecVec::new(node_count),
2362 css_props: FlatVecVec::new(node_count),
2363
2364 computed_values: InheritedValues::new(),
2365 compact_cache: None,
2366 global_css_props: Vec::new(),
2367 resolved_font_sizes_px: crate::sync::OnceLock::new(),
2368 }
2369 }
2370
2371 pub fn invalidate_resolved_font_sizes(&mut self) {
2377 self.resolved_font_sizes_px = crate::sync::OnceLock::new();
2378 }
2379
2380 pub fn append(&mut self, other: &mut Self) {
2381 self.user_overridden_properties
2382 .append(&mut other.user_overridden_properties);
2383 if self.dynamic_context.is_none() {
2386 self.dynamic_context = other.dynamic_context.take();
2387 }
2388 self.cascaded_props.extend_from(&mut other.cascaded_props);
2389 self.css_props.extend_from(&mut other.css_props);
2390 self.computed_values.append(&mut other.computed_values);
2391
2392 self.node_count += other.node_count;
2393 self.resolved_font_sizes_px = crate::sync::OnceLock::new();
2395
2396 self.compact_cache = None;
2398 }
2399
2400 pub fn is_horizontal_overflow_visible(
2401 &self,
2402 node_data: &NodeData,
2403 node_id: &NodeId,
2404 node_state: &StyledNodeState,
2405 ) -> bool {
2406 self.get_overflow_x(node_data, node_id, node_state)
2407 .and_then(|p| p.get_property_or_default())
2408 .unwrap_or_default()
2409 .is_overflow_visible()
2410 }
2411
2412 pub fn is_vertical_overflow_visible(
2413 &self,
2414 node_data: &NodeData,
2415 node_id: &NodeId,
2416 node_state: &StyledNodeState,
2417 ) -> bool {
2418 self.get_overflow_y(node_data, node_id, node_state)
2419 .and_then(|p| p.get_property_or_default())
2420 .unwrap_or_default()
2421 .is_overflow_visible()
2422 }
2423
2424 pub fn is_horizontal_overflow_hidden(
2425 &self,
2426 node_data: &NodeData,
2427 node_id: &NodeId,
2428 node_state: &StyledNodeState,
2429 ) -> bool {
2430 self.get_overflow_x(node_data, node_id, node_state)
2431 .and_then(|p| p.get_property_or_default())
2432 .unwrap_or_default()
2433 .is_overflow_hidden()
2434 }
2435
2436 pub fn is_vertical_overflow_hidden(
2437 &self,
2438 node_data: &NodeData,
2439 node_id: &NodeId,
2440 node_state: &StyledNodeState,
2441 ) -> bool {
2442 self.get_overflow_y(node_data, node_id, node_state)
2443 .and_then(|p| p.get_property_or_default())
2444 .unwrap_or_default()
2445 .is_overflow_hidden()
2446 }
2447
2448 #[must_use]
2453 pub fn get_user_override(
2454 &self,
2455 node_id: &NodeId,
2456 css_property_type: &CssPropertyType,
2457 ) -> Option<&CssProperty> {
2458 let v = self.user_overridden_properties.get(node_id.index())?;
2459 v.binary_search_by_key(css_property_type, |(k, _)| *k)
2460 .ok()
2461 .map(|idx| &v[idx].1)
2462 }
2463
2464 #[must_use]
2470 pub fn has_own_declaration(
2471 &self,
2472 node_data: &NodeData,
2473 node_id: &NodeId,
2474 css_property_type: &CssPropertyType,
2475 ) -> bool {
2476 if node_data
2477 .style
2478 .iter_inline_properties()
2479 .any(|(p, _)| p.get_type() == *css_property_type)
2480 {
2481 return true;
2482 }
2483 self.css_props
2484 .get_slice(node_id.index())
2485 .iter()
2486 .any(|p| p.prop_type == *css_property_type)
2487 }
2488
2489 pub fn get_text_color_or_default(
2490 &self,
2491 node_data: &NodeData,
2492 node_id: &NodeId,
2493 node_state: &StyledNodeState,
2494 ) -> StyleTextColor {
2495 use azul_css::defaults::DEFAULT_TEXT_COLOR;
2496 self.get_text_color(node_data, node_id, node_state)
2497 .and_then(|fs| fs.get_property().copied())
2498 .unwrap_or(DEFAULT_TEXT_COLOR)
2499 }
2500
2501 pub fn get_font_id_or_default(
2503 &self,
2504 node_data: &NodeData,
2505 node_id: &NodeId,
2506 node_state: &StyledNodeState,
2507 ) -> StyleFontFamilyVec {
2508 use azul_css::defaults::DEFAULT_FONT_ID;
2509 let default_font_id = vec![StyleFontFamily::System(AzString::from_const_str(
2510 DEFAULT_FONT_ID,
2511 ))]
2512 .into();
2513 let font_family_opt = self.get_font_family(node_data, node_id, node_state);
2514
2515 font_family_opt
2516 .as_ref()
2517 .and_then(|family| Some(family.get_property()?.clone()))
2518 .unwrap_or(default_font_id)
2519 }
2520
2521 pub fn get_font_size_or_default(
2522 &self,
2523 node_data: &NodeData,
2524 node_id: &NodeId,
2525 node_state: &StyledNodeState,
2526 ) -> StyleFontSize {
2527 use azul_css::defaults::DEFAULT_FONT_SIZE;
2528 self.get_font_size(node_data, node_id, node_state)
2529 .and_then(|fs| fs.get_property().copied())
2530 .unwrap_or(DEFAULT_FONT_SIZE)
2531 }
2532
2533 pub fn has_border(
2534 &self,
2535 node_data: &NodeData,
2536 node_id: &NodeId,
2537 node_state: &StyledNodeState,
2538 ) -> bool {
2539 self.get_border_left_width(node_data, node_id, node_state)
2540 .is_some()
2541 || self
2542 .get_border_right_width(node_data, node_id, node_state)
2543 .is_some()
2544 || self
2545 .get_border_top_width(node_data, node_id, node_state)
2546 .is_some()
2547 || self
2548 .get_border_bottom_width(node_data, node_id, node_state)
2549 .is_some()
2550 }
2551
2552 pub fn has_box_shadow(
2553 &self,
2554 node_data: &NodeData,
2555 node_id: &NodeId,
2556 node_state: &StyledNodeState,
2557 ) -> bool {
2558 self.get_box_shadow_left(node_data, node_id, node_state)
2559 .is_some()
2560 || self
2561 .get_box_shadow_right(node_data, node_id, node_state)
2562 .is_some()
2563 || self
2564 .get_box_shadow_top(node_data, node_id, node_state)
2565 .is_some()
2566 || self
2567 .get_box_shadow_bottom(node_data, node_id, node_state)
2568 .is_some()
2569 }
2570
2571 pub fn get_property<'a>(
2572 &'a self,
2573 node_data: &'a NodeData,
2574 node_id: &NodeId,
2575 node_state: &StyledNodeState,
2576 css_property_type: &CssPropertyType,
2577 ) -> Option<&'a CssProperty> {
2578 #[cfg(feature = "std")]
2595 {
2596 static PROP_COUNT_ENABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2597 let enabled = *PROP_COUNT_ENABLED.get_or_init(crate::profile::cascade_enabled);
2598 if enabled {
2599 let _ = PROP_COUNTS.try_with(|c| {
2606 *c.borrow_mut()
2607 .entry(Self::css_prop_type_label(css_property_type))
2608 .or_insert(0) += 1;
2609 });
2610 }
2611 }
2612
2613 self.get_property_slow(node_data, node_id, node_state, css_property_type)
2617 }
2618
2619 #[cfg(feature = "std")]
2620 #[allow(clippy::trivially_copy_pass_by_ref)] fn css_prop_type_label(t: &CssPropertyType) -> &'static str {
2622 use std::sync::{Mutex, OnceLock};
2627 static TABLE: OnceLock<Mutex<std::collections::HashMap<CssPropertyType, &'static str>>> =
2628 OnceLock::new();
2629 let m = TABLE.get_or_init(|| Mutex::new(std::collections::HashMap::new()));
2630 let mut g = m.lock().expect("AZ_PROP_COUNT label table poisoned");
2631 if let Some(s) = g.get(t) {
2632 return s;
2633 }
2634 let s: String = std::format!("{t:?}");
2635 let leaked: &'static str = std::boxed::Box::leak(s.into_boxed_str());
2636 g.insert(*t, leaked);
2637 leaked
2638 }
2639
2640 #[allow(clippy::trivially_copy_pass_by_ref)] #[allow(clippy::too_many_lines)] pub(crate) fn get_property_slow<'a>(
2646 &'a self,
2647 node_data: &'a NodeData,
2648 node_id: &NodeId,
2649 node_state: &StyledNodeState,
2650 css_property_type: &CssPropertyType,
2651 ) -> Option<&'a CssProperty> {
2652 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
2653
2654 let ctx = self.dynamic_context.as_deref();
2664 let matches_pseudo_state = |conds: &azul_css::dynamic_selector::DynamicSelectorVec,
2665 state: PseudoStateType|
2666 -> bool {
2667 let conditions = conds.as_slice();
2668 if conditions.is_empty() {
2669 state == PseudoStateType::Normal
2670 } else {
2671 conditions.iter().all(|c| match c {
2672 DynamicSelector::PseudoState(s) => *s == state,
2673 non_pseudo => ctx.is_some_and(|ctx| non_pseudo.matches(ctx)),
2674 })
2675 }
2676 };
2677
2678 if let Some(v) = self.user_overridden_properties.get(node_id.index()) {
2680 if let Ok(idx) = v.binary_search_by_key(css_property_type, |(k, _)| *k) {
2681 return Some(&v[idx].1);
2682 }
2683 }
2684
2685 if node_state.placeholder {
2694 if let Some(p) =
2696 node_data
2697 .style
2698 .iter_inline_properties()
2699 .fold(None, |acc, (prop, conds)| {
2700 if matches_pseudo_state(conds, PseudoStateType::Placeholder)
2701 && prop.get_type() == *css_property_type
2702 {
2703 Some(prop)
2704 } else {
2705 acc
2706 }
2707 })
2708 {
2709 return Some(p);
2710 }
2711
2712 if let Some(p) = Self::find_in_stateful(
2714 self.css_props.get_slice(node_id.index()),
2715 PseudoStateType::Placeholder,
2716 css_property_type,
2717 ) {
2718 return Some(p);
2719 }
2720
2721 if let Some(p) = Self::find_in_stateful(
2723 self.cascaded_props.get_slice(node_id.index()),
2724 PseudoStateType::Placeholder,
2725 css_property_type,
2726 ) {
2727 return Some(p);
2728 }
2729 }
2730
2731 if node_state.focused {
2733 if let Some(p) =
2735 node_data
2736 .style
2737 .iter_inline_properties()
2738 .fold(None, |acc, (prop, conds)| {
2739 if matches_pseudo_state(conds, PseudoStateType::Focus)
2740 && prop.get_type() == *css_property_type
2741 {
2742 Some(prop)
2747 } else {
2748 acc
2749 }
2750 })
2751 {
2752 return Some(p);
2753 }
2754
2755 if let Some(p) = Self::find_in_stateful(
2757 self.css_props.get_slice(node_id.index()),
2758 PseudoStateType::Focus,
2759 css_property_type,
2760 ) {
2761 return Some(p);
2762 }
2763
2764 if let Some(p) = Self::find_in_stateful(
2766 self.cascaded_props.get_slice(node_id.index()),
2767 PseudoStateType::Focus,
2768 css_property_type,
2769 ) {
2770 return Some(p);
2771 }
2772 }
2773
2774 if node_state.seat_focused {
2777 if let Some(p) =
2779 node_data
2780 .style
2781 .iter_inline_properties()
2782 .fold(None, |acc, (prop, conds)| {
2783 if matches_pseudo_state(conds, PseudoStateType::SeatFocus)
2784 && prop.get_type() == *css_property_type
2785 {
2786 Some(prop)
2791 } else {
2792 acc
2793 }
2794 })
2795 {
2796 return Some(p);
2797 }
2798
2799 if let Some(p) = Self::find_in_stateful(
2801 self.css_props.get_slice(node_id.index()),
2802 PseudoStateType::SeatFocus,
2803 css_property_type,
2804 ) {
2805 return Some(p);
2806 }
2807
2808 if let Some(p) = Self::find_in_stateful(
2810 self.cascaded_props.get_slice(node_id.index()),
2811 PseudoStateType::SeatFocus,
2812 css_property_type,
2813 ) {
2814 return Some(p);
2815 }
2816 }
2817
2818 if node_state.active {
2819 if let Some(p) =
2821 node_data
2822 .style
2823 .iter_inline_properties()
2824 .fold(None, |acc, (prop, conds)| {
2825 if matches_pseudo_state(conds, PseudoStateType::Active)
2826 && prop.get_type() == *css_property_type
2827 {
2828 Some(prop)
2833 } else {
2834 acc
2835 }
2836 })
2837 {
2838 return Some(p);
2839 }
2840
2841 if let Some(p) = Self::find_in_stateful(
2843 self.css_props.get_slice(node_id.index()),
2844 PseudoStateType::Active,
2845 css_property_type,
2846 ) {
2847 return Some(p);
2848 }
2849
2850 if let Some(p) = Self::find_in_stateful(
2852 self.cascaded_props.get_slice(node_id.index()),
2853 PseudoStateType::Active,
2854 css_property_type,
2855 ) {
2856 return Some(p);
2857 }
2858 }
2859
2860 if node_state.dragging {
2862 if let Some(p) =
2863 node_data
2864 .style
2865 .iter_inline_properties()
2866 .fold(None, |acc, (prop, conds)| {
2867 if matches_pseudo_state(conds, PseudoStateType::Dragging)
2868 && prop.get_type() == *css_property_type
2869 {
2870 Some(prop)
2875 } else {
2876 acc
2877 }
2878 })
2879 {
2880 return Some(p);
2881 }
2882
2883 if let Some(p) = Self::find_in_stateful(
2884 self.css_props.get_slice(node_id.index()),
2885 PseudoStateType::Dragging,
2886 css_property_type,
2887 ) {
2888 return Some(p);
2889 }
2890
2891 if let Some(p) = Self::find_in_stateful(
2892 self.cascaded_props.get_slice(node_id.index()),
2893 PseudoStateType::Dragging,
2894 css_property_type,
2895 ) {
2896 return Some(p);
2897 }
2898 }
2899
2900 if node_state.drag_over {
2902 if let Some(p) =
2903 node_data
2904 .style
2905 .iter_inline_properties()
2906 .fold(None, |acc, (prop, conds)| {
2907 if matches_pseudo_state(conds, PseudoStateType::DragOver)
2908 && prop.get_type() == *css_property_type
2909 {
2910 Some(prop)
2915 } else {
2916 acc
2917 }
2918 })
2919 {
2920 return Some(p);
2921 }
2922
2923 if let Some(p) = Self::find_in_stateful(
2924 self.css_props.get_slice(node_id.index()),
2925 PseudoStateType::DragOver,
2926 css_property_type,
2927 ) {
2928 return Some(p);
2929 }
2930
2931 if let Some(p) = Self::find_in_stateful(
2932 self.cascaded_props.get_slice(node_id.index()),
2933 PseudoStateType::DragOver,
2934 css_property_type,
2935 ) {
2936 return Some(p);
2937 }
2938 }
2939
2940 if node_state.hover {
2941 if let Some(p) =
2943 node_data
2944 .style
2945 .iter_inline_properties()
2946 .fold(None, |acc, (prop, conds)| {
2947 if matches_pseudo_state(conds, PseudoStateType::Hover)
2948 && prop.get_type() == *css_property_type
2949 {
2950 Some(prop)
2955 } else {
2956 acc
2957 }
2958 })
2959 {
2960 return Some(p);
2961 }
2962
2963 if let Some(p) = Self::find_in_stateful(
2965 self.css_props.get_slice(node_id.index()),
2966 PseudoStateType::Hover,
2967 css_property_type,
2968 ) {
2969 return Some(p);
2970 }
2971
2972 if let Some(p) = Self::find_in_stateful(
2974 self.cascaded_props.get_slice(node_id.index()),
2975 PseudoStateType::Hover,
2976 css_property_type,
2977 ) {
2978 return Some(p);
2979 }
2980 }
2981
2982 if let Some(p) =
2985 node_data
2986 .style
2987 .iter_inline_properties()
2988 .fold(None, |acc, (prop, conds)| {
2989 if matches_pseudo_state(conds, PseudoStateType::Normal)
2990 && prop.get_type() == *css_property_type
2991 {
2992 Some(prop)
2998 } else {
2999 acc
3000 }
3001 })
3002 {
3003 return Some(p);
3004 }
3005
3006 if let Some(p) = Self::find_in_stateful(
3008 self.css_props.get_slice(node_id.index()),
3009 PseudoStateType::Normal,
3010 css_property_type,
3011 ) {
3012 return Some(p);
3013 }
3014
3015 if let Some(p) = self
3019 .global_css_props
3020 .iter()
3021 .find(|p| p.get_type() == *css_property_type)
3022 {
3023 return Some(p);
3024 }
3025
3026 if let Some(p) = Self::find_in_stateful(
3028 self.cascaded_props.get_slice(node_id.index()),
3029 PseudoStateType::Normal,
3030 css_property_type,
3031 ) {
3032 return Some(p);
3033 }
3034
3035 if css_property_type.is_inheritable() {
3038 if let Some(v) = self.computed_values.get(node_id.index(), *css_property_type) {
3039 return Some(&v.property);
3040 }
3041 }
3042
3043 crate::ua_css::get_ua_property(&node_data.node_type, *css_property_type)
3046 }
3047
3048 #[allow(clippy::trivially_copy_pass_by_ref)] pub(crate) fn get_property_with_context<'a>(
3057 &'a self,
3058 node_data: &'a NodeData,
3059 node_id: &NodeId,
3060 context: &DynamicSelectorContext,
3061 css_property_type: &CssPropertyType,
3062 ) -> Option<&'a CssProperty> {
3063 if let Some(v) = self.user_overridden_properties.get(node_id.index()) {
3065 if let Ok(idx) = v.binary_search_by_key(css_property_type, |(k, _)| *k) {
3066 return Some(&v[idx].1);
3067 }
3068 }
3069
3070 let mut last_inline = None;
3078 for (prop, conds) in node_data.style.iter_inline_properties() {
3079 let conditions_match = conds.as_slice().iter().all(|c| c.matches(context));
3080 if prop.get_type() == *css_property_type && conditions_match {
3081 last_inline = Some(prop);
3082 }
3083 }
3084 if let Some(prop) = last_inline {
3085 return Some(prop);
3086 }
3087
3088 let legacy_state = StyledNodeState::from_pseudo_state_flags(&context.pseudo_state);
3090 if let Some(p) = self.get_property(node_data, node_id, &legacy_state, css_property_type) {
3091 return Some(p);
3092 }
3093
3094 None
3095 }
3096
3097 pub(crate) fn check_properties_changed(
3100 node_data: &NodeData,
3101 old_context: &DynamicSelectorContext,
3102 new_context: &DynamicSelectorContext,
3103 ) -> bool {
3104 for (_prop, conds) in node_data.style.iter_inline_properties() {
3105 let was_active = conds.as_slice().iter().all(|c| c.matches(old_context));
3106 let is_active = conds.as_slice().iter().all(|c| c.matches(new_context));
3107 if was_active != is_active {
3108 return true;
3109 }
3110 }
3111 false
3112 }
3113
3114 pub(crate) fn check_layout_properties_changed(
3117 node_data: &NodeData,
3118 old_context: &DynamicSelectorContext,
3119 new_context: &DynamicSelectorContext,
3120 ) -> bool {
3121 for (prop, conds) in node_data.style.iter_inline_properties() {
3122 if !prop.get_type().can_trigger_relayout() {
3124 continue;
3125 }
3126
3127 let was_active = conds.as_slice().iter().all(|c| c.matches(old_context));
3128 let is_active = conds.as_slice().iter().all(|c| c.matches(new_context));
3129 if was_active != is_active {
3130 return true;
3131 }
3132 }
3133 false
3134 }
3135
3136 impl_get_prop!(
3137 get_background_content,
3138 StyleBackgroundContentVecValue,
3139 BackgroundContent,
3140 as_background_content
3141 );
3142
3143 impl_get_prop!(get_hyphens, StyleHyphensValue, Hyphens, as_hyphens);
3144
3145 impl_get_prop!(
3146 get_word_break,
3147 StyleWordBreakValue,
3148 WordBreak,
3149 as_word_break
3150 );
3151
3152 impl_get_prop!(
3153 get_overflow_wrap,
3154 StyleOverflowWrapValue,
3155 OverflowWrap,
3156 as_overflow_wrap
3157 );
3158
3159 impl_get_prop!(
3160 get_line_break,
3161 StyleLineBreakValue,
3162 LineBreak,
3163 as_line_break
3164 );
3165
3166 impl_get_prop!(
3167 get_text_align_last,
3168 StyleTextAlignLastValue,
3169 TextAlignLast,
3170 as_text_align_last
3171 );
3172
3173 impl_get_prop!(
3174 get_text_transform,
3175 StyleTextTransformValue,
3176 TextTransform,
3177 as_text_transform
3178 );
3179
3180 impl_get_prop!(
3181 get_object_fit,
3182 StyleObjectFitValue,
3183 ObjectFit,
3184 as_object_fit
3185 );
3186
3187 impl_get_prop!(
3188 get_text_overflow,
3189 StyleTextOverflowValue,
3190 TextOverflow,
3191 as_text_overflow
3192 );
3193
3194 impl_get_prop!(
3195 get_text_orientation,
3196 StyleTextOrientationValue,
3197 TextOrientation,
3198 as_text_orientation
3199 );
3200
3201 impl_get_prop!(
3202 get_object_position,
3203 StyleObjectPositionValue,
3204 ObjectPosition,
3205 as_object_position
3206 );
3207
3208 impl_get_prop!(
3209 get_aspect_ratio,
3210 StyleAspectRatioValue,
3211 AspectRatio,
3212 as_aspect_ratio
3213 );
3214
3215 impl_get_prop!(get_direction, StyleDirectionValue, Direction, as_direction);
3216
3217 impl_get_prop!(
3218 get_unicode_bidi,
3219 StyleUnicodeBidiValue,
3220 UnicodeBidi,
3221 as_unicode_bidi
3222 );
3223
3224 impl_get_prop!(
3225 get_text_box_trim,
3226 StyleTextBoxTrimValue,
3227 TextBoxTrim,
3228 as_text_box_trim
3229 );
3230
3231 impl_get_prop!(
3232 get_text_box_edge,
3233 StyleTextBoxEdgeValue,
3234 TextBoxEdge,
3235 as_text_box_edge
3236 );
3237
3238 impl_get_prop!(
3239 get_dominant_baseline,
3240 StyleDominantBaselineValue,
3241 DominantBaseline,
3242 as_dominant_baseline
3243 );
3244
3245 impl_get_prop!(
3246 get_alignment_baseline,
3247 StyleAlignmentBaselineValue,
3248 AlignmentBaseline,
3249 as_alignment_baseline
3250 );
3251
3252 impl_get_prop!(
3253 get_baseline_source,
3254 StyleBaselineSourceValue,
3255 BaselineSource,
3256 as_baseline_source
3257 );
3258
3259 impl_get_prop!(
3260 get_line_fit_edge,
3261 StyleLineFitEdgeValue,
3262 LineFitEdge,
3263 as_line_fit_edge
3264 );
3265
3266 impl_get_prop!(
3267 get_initial_letter_align,
3268 StyleInitialLetterAlignValue,
3269 InitialLetterAlign,
3270 as_initial_letter_align
3271 );
3272
3273 impl_get_prop!(
3274 get_initial_letter_wrap,
3275 StyleInitialLetterWrapValue,
3276 InitialLetterWrap,
3277 as_initial_letter_wrap
3278 );
3279
3280 impl_get_prop!(
3281 get_scrollbar_gutter,
3282 StyleScrollbarGutterValue,
3283 ScrollbarGutter,
3284 as_scrollbar_gutter
3285 );
3286
3287 impl_get_prop!(
3288 get_overflow_clip_margin,
3289 StyleOverflowClipMarginValue,
3290 OverflowClipMargin,
3291 as_overflow_clip_margin
3292 );
3293
3294 impl_get_prop!(get_clip, StyleClipRectValue, Clip, as_clip);
3295
3296 impl_get_prop!(
3297 get_white_space,
3298 StyleWhiteSpaceValue,
3299 WhiteSpace,
3300 as_white_space
3301 );
3302 impl_get_prop!(
3303 get_background_position,
3304 StyleBackgroundPositionVecValue,
3305 BackgroundPosition,
3306 as_background_position
3307 );
3308 impl_get_prop!(
3309 get_background_size,
3310 StyleBackgroundSizeVecValue,
3311 BackgroundSize,
3312 as_background_size
3313 );
3314 impl_get_prop!(
3315 get_background_repeat,
3316 StyleBackgroundRepeatVecValue,
3317 BackgroundRepeat,
3318 as_background_repeat
3319 );
3320 impl_get_prop!(get_font_size, StyleFontSizeValue, FontSize, as_font_size);
3321 impl_get_prop!(
3322 get_font_family,
3323 StyleFontFamilyVecValue,
3324 FontFamily,
3325 as_font_family
3326 );
3327 impl_get_prop!(
3328 get_font_weight,
3329 StyleFontWeightValue,
3330 FontWeight,
3331 as_font_weight
3332 );
3333 impl_get_prop!(
3334 get_font_style,
3335 StyleFontStyleValue,
3336 FontStyle,
3337 as_font_style
3338 );
3339 impl_get_prop!(
3340 get_text_color,
3341 StyleTextColorValue,
3342 TextColor,
3343 as_text_color
3344 );
3345 impl_get_prop!(
3346 get_text_indent,
3347 StyleTextIndentValue,
3348 TextIndent,
3349 as_text_indent
3350 );
3351 impl_get_prop!(
3352 get_initial_letter,
3353 StyleInitialLetterValue,
3354 InitialLetter,
3355 as_initial_letter
3356 );
3357 impl_get_prop!(
3358 get_line_clamp,
3359 StyleLineClampValue,
3360 LineClamp,
3361 as_line_clamp
3362 );
3363 impl_get_prop!(
3364 get_hanging_punctuation,
3365 StyleHangingPunctuationValue,
3366 HangingPunctuation,
3367 as_hanging_punctuation
3368 );
3369 impl_get_prop!(
3370 get_text_combine_upright,
3371 StyleTextCombineUprightValue,
3372 TextCombineUpright,
3373 as_text_combine_upright
3374 );
3375 impl_get_prop!(
3376 get_exclusion_margin,
3377 StyleExclusionMarginValue,
3378 ExclusionMargin,
3379 as_exclusion_margin
3380 );
3381 impl_get_prop!(
3382 get_hyphenation_language,
3383 StyleHyphenationLanguageValue,
3384 HyphenationLanguage,
3385 as_hyphenation_language
3386 );
3387 impl_get_prop!(get_caret_color, CaretColorValue, CaretColor, as_caret_color);
3388
3389 impl_get_prop!(get_caret_width, CaretWidthValue, CaretWidth, as_caret_width);
3390
3391 impl_get_prop!(
3392 get_caret_animation_duration,
3393 CaretAnimationDurationValue,
3394 CaretAnimationDuration,
3395 as_caret_animation_duration
3396 );
3397
3398 impl_get_prop!(
3399 get_selection_background_color,
3400 SelectionBackgroundColorValue,
3401 SelectionBackgroundColor,
3402 as_selection_background_color
3403 );
3404
3405 impl_get_prop!(
3406 get_selection_color,
3407 SelectionColorValue,
3408 SelectionColor,
3409 as_selection_color
3410 );
3411
3412 impl_get_prop!(
3413 get_selection_radius,
3414 SelectionRadiusValue,
3415 SelectionRadius,
3416 as_selection_radius
3417 );
3418
3419 impl_get_prop!(
3420 get_text_justify,
3421 LayoutTextJustifyValue,
3422 TextJustify,
3423 as_text_justify
3424 );
3425
3426 impl_get_prop!(get_z_index, LayoutZIndexValue, ZIndex, as_z_index);
3427
3428 impl_get_prop!(
3429 get_flex_basis,
3430 LayoutFlexBasisValue,
3431 FlexBasis,
3432 as_flex_basis
3433 );
3434
3435 impl_get_prop!(
3436 get_column_gap,
3437 LayoutColumnGapValue,
3438 ColumnGap,
3439 as_column_gap
3440 );
3441
3442 impl_get_prop!(get_row_gap, LayoutRowGapValue, RowGap, as_row_gap);
3443
3444 impl_get_prop!(
3445 get_grid_template_columns,
3446 LayoutGridTemplateColumnsValue,
3447 GridTemplateColumns,
3448 as_grid_template_columns
3449 );
3450
3451 impl_get_prop!(
3452 get_grid_template_rows,
3453 LayoutGridTemplateRowsValue,
3454 GridTemplateRows,
3455 as_grid_template_rows
3456 );
3457
3458 impl_get_prop!(
3459 get_grid_auto_columns,
3460 LayoutGridAutoColumnsValue,
3461 GridAutoColumns,
3462 as_grid_auto_columns
3463 );
3464
3465 impl_get_prop!(
3466 get_grid_auto_rows,
3467 LayoutGridAutoRowsValue,
3468 GridAutoRows,
3469 as_grid_auto_rows
3470 );
3471
3472 impl_get_prop!(
3473 get_grid_column,
3474 LayoutGridColumnValue,
3475 GridColumn,
3476 as_grid_column
3477 );
3478
3479 impl_get_prop!(get_grid_row, LayoutGridRowValue, GridRow, as_grid_row);
3480
3481 impl_get_prop!(
3482 get_grid_auto_flow,
3483 LayoutGridAutoFlowValue,
3484 GridAutoFlow,
3485 as_grid_auto_flow
3486 );
3487
3488 impl_get_prop!(
3489 get_justify_self,
3490 LayoutJustifySelfValue,
3491 JustifySelf,
3492 as_justify_self
3493 );
3494
3495 impl_get_prop!(
3496 get_justify_items,
3497 LayoutJustifyItemsValue,
3498 JustifyItems,
3499 as_justify_items
3500 );
3501
3502 impl_get_prop!(get_gap, LayoutGapValue, Gap, as_gap);
3503
3504 #[allow(clippy::trivially_copy_pass_by_ref)] pub(crate) fn get_grid_gap<'a>(
3507 &'a self,
3508 node_data: &'a NodeData,
3509 node_id: &NodeId,
3510 node_state: &StyledNodeState,
3511 ) -> Option<&'a LayoutGapValue> {
3512 self.get_property(node_data, node_id, node_state, &CssPropertyType::GridGap)
3513 .and_then(|p| p.as_grid_gap())
3514 }
3515
3516 impl_get_prop!(
3517 get_align_self,
3518 LayoutAlignSelfValue,
3519 AlignSelf,
3520 as_align_self
3521 );
3522
3523 impl_get_prop!(get_font, StyleFontValue, Font, as_font);
3524
3525 impl_get_prop!(
3526 get_writing_mode,
3527 LayoutWritingModeValue,
3528 WritingMode,
3529 as_writing_mode
3530 );
3531
3532 impl_get_prop!(get_clear, LayoutClearValue, Clear, as_clear);
3533
3534 impl_get_prop!(
3535 get_shape_outside,
3536 ShapeOutsideValue,
3537 ShapeOutside,
3538 as_shape_outside
3539 );
3540
3541 impl_get_prop!(
3542 get_shape_inside,
3543 ShapeInsideValue,
3544 ShapeInside,
3545 as_shape_inside
3546 );
3547
3548 impl_get_prop!(get_clip_path, ClipPathValue, ClipPath, as_clip_path);
3549
3550 pub fn get_scrollbar_track<'a>(
3552 &'a self,
3553 node_data: &'a NodeData,
3554 node_id: &NodeId,
3555 node_state: &StyledNodeState,
3556 ) -> Option<&'a StyleBackgroundContentValue> {
3557 self.get_property(
3558 node_data,
3559 node_id,
3560 node_state,
3561 &CssPropertyType::ScrollbarTrack,
3562 )
3563 .and_then(|p| p.as_scrollbar_track())
3564 }
3565
3566 pub fn get_scrollbar_thumb<'a>(
3568 &'a self,
3569 node_data: &'a NodeData,
3570 node_id: &NodeId,
3571 node_state: &StyledNodeState,
3572 ) -> Option<&'a StyleBackgroundContentValue> {
3573 self.get_property(
3574 node_data,
3575 node_id,
3576 node_state,
3577 &CssPropertyType::ScrollbarThumb,
3578 )
3579 .and_then(|p| p.as_scrollbar_thumb())
3580 }
3581
3582 pub fn get_scrollbar_button<'a>(
3584 &'a self,
3585 node_data: &'a NodeData,
3586 node_id: &NodeId,
3587 node_state: &StyledNodeState,
3588 ) -> Option<&'a StyleBackgroundContentValue> {
3589 self.get_property(
3590 node_data,
3591 node_id,
3592 node_state,
3593 &CssPropertyType::ScrollbarButton,
3594 )
3595 .and_then(|p| p.as_scrollbar_button())
3596 }
3597
3598 pub fn get_scrollbar_corner<'a>(
3600 &'a self,
3601 node_data: &'a NodeData,
3602 node_id: &NodeId,
3603 node_state: &StyledNodeState,
3604 ) -> Option<&'a StyleBackgroundContentValue> {
3605 self.get_property(
3606 node_data,
3607 node_id,
3608 node_state,
3609 &CssPropertyType::ScrollbarCorner,
3610 )
3611 .and_then(|p| p.as_scrollbar_corner())
3612 }
3613
3614 pub fn get_scrollbar_resizer<'a>(
3616 &'a self,
3617 node_data: &'a NodeData,
3618 node_id: &NodeId,
3619 node_state: &StyledNodeState,
3620 ) -> Option<&'a StyleBackgroundContentValue> {
3621 self.get_property(
3622 node_data,
3623 node_id,
3624 node_state,
3625 &CssPropertyType::ScrollbarResizer,
3626 )
3627 .and_then(|p| p.as_scrollbar_resizer())
3628 }
3629
3630 impl_get_prop!(
3631 get_scrollbar_width,
3632 LayoutScrollbarWidthValue,
3633 ScrollbarWidth,
3634 as_scrollbar_width
3635 );
3636 impl_get_prop!(
3637 get_overscroll_behavior_x,
3638 OverscrollBehaviorValue,
3639 OverscrollBehaviorX,
3640 as_overscroll_behavior_x
3641 );
3642 impl_get_prop!(
3643 get_overscroll_behavior_y,
3644 OverscrollBehaviorValue,
3645 OverscrollBehaviorY,
3646 as_overscroll_behavior_y
3647 );
3648
3649 impl_get_prop!(
3650 get_scrollbar_color,
3651 StyleScrollbarColorValue,
3652 ScrollbarColor,
3653 as_scrollbar_color
3654 );
3655
3656 impl_get_prop!(
3657 get_scrollbar_visibility,
3658 ScrollbarVisibilityModeValue,
3659 ScrollbarVisibility,
3660 as_scrollbar_visibility
3661 );
3662
3663 impl_get_prop!(
3664 get_scrollbar_fade_delay,
3665 ScrollbarFadeDelayValue,
3666 ScrollbarFadeDelay,
3667 as_scrollbar_fade_delay
3668 );
3669
3670 impl_get_prop!(
3671 get_scrollbar_fade_duration,
3672 ScrollbarFadeDurationValue,
3673 ScrollbarFadeDuration,
3674 as_scrollbar_fade_duration
3675 );
3676
3677 impl_get_prop!(
3678 get_visibility,
3679 StyleVisibilityValue,
3680 Visibility,
3681 as_visibility
3682 );
3683
3684 impl_get_prop!(
3685 get_break_before,
3686 PageBreakValue,
3687 BreakBefore,
3688 as_break_before
3689 );
3690
3691 impl_get_prop!(get_break_after, PageBreakValue, BreakAfter, as_break_after);
3692
3693 impl_get_prop!(
3694 get_break_inside,
3695 BreakInsideValue,
3696 BreakInside,
3697 as_break_inside
3698 );
3699
3700 impl_get_prop!(get_orphans, OrphansValue, Orphans, as_orphans);
3701
3702 impl_get_prop!(get_widows, WidowsValue, Widows, as_widows);
3703
3704 impl_get_prop!(
3705 get_box_decoration_break,
3706 BoxDecorationBreakValue,
3707 BoxDecorationBreak,
3708 as_box_decoration_break
3709 );
3710
3711 impl_get_prop!(
3712 get_column_count,
3713 ColumnCountValue,
3714 ColumnCount,
3715 as_column_count
3716 );
3717
3718 impl_get_prop!(
3719 get_column_width,
3720 ColumnWidthValue,
3721 ColumnWidth,
3722 as_column_width
3723 );
3724
3725 impl_get_prop!(get_column_span, ColumnSpanValue, ColumnSpan, as_column_span);
3726
3727 impl_get_prop!(get_column_fill, ColumnFillValue, ColumnFill, as_column_fill);
3728
3729 impl_get_prop!(
3730 get_column_rule_width,
3731 ColumnRuleWidthValue,
3732 ColumnRuleWidth,
3733 as_column_rule_width
3734 );
3735
3736 impl_get_prop!(
3737 get_column_rule_style,
3738 ColumnRuleStyleValue,
3739 ColumnRuleStyle,
3740 as_column_rule_style
3741 );
3742
3743 impl_get_prop!(
3744 get_column_rule_color,
3745 ColumnRuleColorValue,
3746 ColumnRuleColor,
3747 as_column_rule_color
3748 );
3749
3750 impl_get_prop!(get_flow_into, FlowIntoValue, FlowInto, as_flow_into);
3751
3752 impl_get_prop!(get_flow_from, FlowFromValue, FlowFrom, as_flow_from);
3753
3754 impl_get_prop!(
3755 get_shape_margin,
3756 ShapeMarginValue,
3757 ShapeMargin,
3758 as_shape_margin
3759 );
3760
3761 impl_get_prop!(
3762 get_shape_image_threshold,
3763 ShapeImageThresholdValue,
3764 ShapeImageThreshold,
3765 as_shape_image_threshold
3766 );
3767
3768 impl_get_prop!(get_content, ContentValue, Content, as_content);
3769
3770 impl_get_prop!(
3771 get_counter_reset,
3772 CounterResetValue,
3773 CounterReset,
3774 as_counter_reset
3775 );
3776
3777 impl_get_prop!(
3778 get_counter_increment,
3779 CounterIncrementValue,
3780 CounterIncrement,
3781 as_counter_increment
3782 );
3783
3784 impl_get_prop!(get_string_set, StringSetValue, StringSet, as_string_set);
3785 impl_get_prop!(
3786 get_text_align,
3787 StyleTextAlignValue,
3788 TextAlign,
3789 as_text_align
3790 );
3791 impl_get_prop!(
3792 get_user_select,
3793 StyleUserSelectValue,
3794 UserSelect,
3795 as_user_select
3796 );
3797 impl_get_prop!(
3798 get_text_decoration,
3799 StyleTextDecorationValue,
3800 TextDecoration,
3801 as_text_decoration
3802 );
3803 impl_get_prop!(
3804 get_vertical_align,
3805 StyleVerticalAlignValue,
3806 VerticalAlign,
3807 as_vertical_align
3808 );
3809 impl_get_prop!(
3810 get_line_height,
3811 StyleLineHeightValue,
3812 LineHeight,
3813 as_line_height
3814 );
3815 impl_get_prop!(
3816 get_letter_spacing,
3817 StyleLetterSpacingValue,
3818 LetterSpacing,
3819 as_letter_spacing
3820 );
3821 impl_get_prop!(
3822 get_word_spacing,
3823 StyleWordSpacingValue,
3824 WordSpacing,
3825 as_word_spacing
3826 );
3827 impl_get_prop!(get_tab_size, StyleTabSizeValue, TabSize, as_tab_size);
3828 impl_get_prop!(get_cursor, StyleCursorValue, Cursor, as_cursor);
3829 impl_get_prop!(
3830 get_box_shadow_left,
3831 StyleBoxShadowValue,
3832 BoxShadowLeft,
3833 as_box_shadow_left
3834 );
3835 impl_get_prop!(
3836 get_box_shadow_right,
3837 StyleBoxShadowValue,
3838 BoxShadowRight,
3839 as_box_shadow_right
3840 );
3841 impl_get_prop!(
3842 get_box_shadow_top,
3843 StyleBoxShadowValue,
3844 BoxShadowTop,
3845 as_box_shadow_top
3846 );
3847 impl_get_prop!(
3848 get_box_shadow_bottom,
3849 StyleBoxShadowValue,
3850 BoxShadowBottom,
3851 as_box_shadow_bottom
3852 );
3853 impl_get_prop!(
3854 get_border_top_color,
3855 StyleBorderTopColorValue,
3856 BorderTopColor,
3857 as_border_top_color
3858 );
3859 impl_get_prop!(
3860 get_border_left_color,
3861 StyleBorderLeftColorValue,
3862 BorderLeftColor,
3863 as_border_left_color
3864 );
3865 impl_get_prop!(
3866 get_border_right_color,
3867 StyleBorderRightColorValue,
3868 BorderRightColor,
3869 as_border_right_color
3870 );
3871 impl_get_prop!(
3872 get_border_bottom_color,
3873 StyleBorderBottomColorValue,
3874 BorderBottomColor,
3875 as_border_bottom_color
3876 );
3877 impl_get_prop!(
3878 get_border_top_style,
3879 StyleBorderTopStyleValue,
3880 BorderTopStyle,
3881 as_border_top_style
3882 );
3883 impl_get_prop!(
3884 get_border_left_style,
3885 StyleBorderLeftStyleValue,
3886 BorderLeftStyle,
3887 as_border_left_style
3888 );
3889 impl_get_prop!(
3890 get_border_right_style,
3891 StyleBorderRightStyleValue,
3892 BorderRightStyle,
3893 as_border_right_style
3894 );
3895 impl_get_prop!(
3896 get_border_bottom_style,
3897 StyleBorderBottomStyleValue,
3898 BorderBottomStyle,
3899 as_border_bottom_style
3900 );
3901 impl_get_prop!(
3902 get_border_top_left_radius,
3903 StyleBorderTopLeftRadiusValue,
3904 BorderTopLeftRadius,
3905 as_border_top_left_radius
3906 );
3907 impl_get_prop!(
3908 get_border_top_right_radius,
3909 StyleBorderTopRightRadiusValue,
3910 BorderTopRightRadius,
3911 as_border_top_right_radius
3912 );
3913 impl_get_prop!(
3914 get_border_bottom_left_radius,
3915 StyleBorderBottomLeftRadiusValue,
3916 BorderBottomLeftRadius,
3917 as_border_bottom_left_radius
3918 );
3919 impl_get_prop!(
3920 get_border_bottom_right_radius,
3921 StyleBorderBottomRightRadiusValue,
3922 BorderBottomRightRadius,
3923 as_border_bottom_right_radius
3924 );
3925 impl_get_prop!(get_opacity, StyleOpacityValue, Opacity, as_opacity);
3926 impl_get_prop!(
3927 get_transform,
3928 StyleTransformVecValue,
3929 Transform,
3930 as_transform
3931 );
3932 impl_get_prop!(
3933 get_transform_origin,
3934 StyleTransformOriginValue,
3935 TransformOrigin,
3936 as_transform_origin
3937 );
3938 impl_get_prop!(
3939 get_perspective_origin,
3940 StylePerspectiveOriginValue,
3941 PerspectiveOrigin,
3942 as_perspective_origin
3943 );
3944 impl_get_prop!(
3945 get_backface_visibility,
3946 StyleBackfaceVisibilityValue,
3947 BackfaceVisibility,
3948 as_backface_visibility
3949 );
3950 impl_get_prop!(
3951 get_app_region,
3952 StyleAppRegionValue,
3953 AppRegion,
3954 as_app_region
3955 );
3956 impl_get_prop!(
3957 get_spatial_navigation_action,
3958 StyleSpatialNavigationActionValue,
3959 SpatialNavigationAction,
3960 as_spatial_navigation_action
3961 );
3962 impl_get_prop!(
3963 get_spatial_navigation_contain,
3964 StyleSpatialNavigationContainValue,
3965 SpatialNavigationContain,
3966 as_spatial_navigation_contain
3967 );
3968 impl_get_prop!(get_display, LayoutDisplayValue, Display, as_display);
3969 impl_get_prop!(get_float, LayoutFloatValue, Float, as_float);
3970 impl_get_prop!(
3971 get_box_sizing,
3972 LayoutBoxSizingValue,
3973 BoxSizing,
3974 as_box_sizing
3975 );
3976 impl_get_prop!(get_width, LayoutWidthValue, Width, as_width);
3977 impl_get_prop!(get_height, LayoutHeightValue, Height, as_height);
3978 impl_get_prop!(get_min_width, LayoutMinWidthValue, MinWidth, as_min_width);
3979 impl_get_prop!(
3980 get_min_height,
3981 LayoutMinHeightValue,
3982 MinHeight,
3983 as_min_height
3984 );
3985 impl_get_prop!(get_max_width, LayoutMaxWidthValue, MaxWidth, as_max_width);
3986 impl_get_prop!(
3987 get_max_height,
3988 LayoutMaxHeightValue,
3989 MaxHeight,
3990 as_max_height
3991 );
3992 impl_get_prop!(get_position, LayoutPositionValue, Position, as_position);
3993 impl_get_prop!(get_top, LayoutTopValue, Top, as_top);
3994 impl_get_prop!(get_bottom, LayoutInsetBottomValue, Bottom, as_bottom);
3995 impl_get_prop!(get_right, LayoutRightValue, Right, as_right);
3996 impl_get_prop!(get_left, LayoutLeftValue, Left, as_left);
3997 impl_get_prop!(
3998 get_padding_top,
3999 LayoutPaddingTopValue,
4000 PaddingTop,
4001 as_padding_top
4002 );
4003 impl_get_prop!(
4004 get_padding_bottom,
4005 LayoutPaddingBottomValue,
4006 PaddingBottom,
4007 as_padding_bottom
4008 );
4009 impl_get_prop!(
4010 get_padding_left,
4011 LayoutPaddingLeftValue,
4012 PaddingLeft,
4013 as_padding_left
4014 );
4015 impl_get_prop!(
4016 get_padding_right,
4017 LayoutPaddingRightValue,
4018 PaddingRight,
4019 as_padding_right
4020 );
4021 impl_get_prop!(
4022 get_margin_top,
4023 LayoutMarginTopValue,
4024 MarginTop,
4025 as_margin_top
4026 );
4027 impl_get_prop!(
4028 get_margin_bottom,
4029 LayoutMarginBottomValue,
4030 MarginBottom,
4031 as_margin_bottom
4032 );
4033 impl_get_prop!(
4034 get_margin_left,
4035 LayoutMarginLeftValue,
4036 MarginLeft,
4037 as_margin_left
4038 );
4039 impl_get_prop!(
4040 get_margin_right,
4041 LayoutMarginRightValue,
4042 MarginRight,
4043 as_margin_right
4044 );
4045 impl_get_prop!(
4046 get_border_top_width,
4047 LayoutBorderTopWidthValue,
4048 BorderTopWidth,
4049 as_border_top_width
4050 );
4051 impl_get_prop!(
4052 get_border_left_width,
4053 LayoutBorderLeftWidthValue,
4054 BorderLeftWidth,
4055 as_border_left_width
4056 );
4057 impl_get_prop!(
4058 get_border_right_width,
4059 LayoutBorderRightWidthValue,
4060 BorderRightWidth,
4061 as_border_right_width
4062 );
4063 impl_get_prop!(
4064 get_border_bottom_width,
4065 LayoutBorderBottomWidthValue,
4066 BorderBottomWidth,
4067 as_border_bottom_width
4068 );
4069 impl_get_prop!(
4070 get_overflow_x,
4071 LayoutOverflowValue,
4072 OverflowX,
4073 as_overflow_x
4074 );
4075 impl_get_prop!(
4076 get_overflow_y,
4077 LayoutOverflowValue,
4078 OverflowY,
4079 as_overflow_y
4080 );
4081 impl_get_prop!(
4082 get_overflow_block,
4083 LayoutOverflowValue,
4084 OverflowBlock,
4085 as_overflow_block
4086 );
4087 impl_get_prop!(
4088 get_overflow_inline,
4089 LayoutOverflowValue,
4090 OverflowInline,
4091 as_overflow_inline
4092 );
4093 impl_get_prop!(
4094 get_flex_direction,
4095 LayoutFlexDirectionValue,
4096 FlexDirection,
4097 as_flex_direction
4098 );
4099 impl_get_prop!(get_flex_wrap, LayoutFlexWrapValue, FlexWrap, as_flex_wrap);
4100 impl_get_prop!(get_flex_grow, LayoutFlexGrowValue, FlexGrow, as_flex_grow);
4101 impl_get_prop!(
4102 get_flex_shrink,
4103 LayoutFlexShrinkValue,
4104 FlexShrink,
4105 as_flex_shrink
4106 );
4107 impl_get_prop!(
4108 get_justify_content,
4109 LayoutJustifyContentValue,
4110 JustifyContent,
4111 as_justify_content
4112 );
4113 impl_get_prop!(
4114 get_align_items,
4115 LayoutAlignItemsValue,
4116 AlignItems,
4117 as_align_items
4118 );
4119 impl_get_prop!(
4120 get_align_content,
4121 LayoutAlignContentValue,
4122 AlignContent,
4123 as_align_content
4124 );
4125 impl_get_prop!(
4126 get_mix_blend_mode,
4127 StyleMixBlendModeValue,
4128 MixBlendMode,
4129 as_mix_blend_mode
4130 );
4131 impl_get_prop!(get_filter, StyleFilterVecValue, Filter, as_filter);
4132 impl_get_prop!(
4133 get_backdrop_filter,
4134 StyleFilterVecValue,
4135 BackdropFilter,
4136 as_backdrop_filter
4137 );
4138 impl_get_prop!(
4139 get_text_shadow,
4140 StyleBoxShadowValue,
4141 TextShadow,
4142 as_text_shadow
4143 );
4144 impl_get_prop!(
4145 get_list_style_type,
4146 StyleListStyleTypeValue,
4147 ListStyleType,
4148 as_list_style_type
4149 );
4150 impl_get_prop!(
4151 get_list_style_position,
4152 StyleListStylePositionValue,
4153 ListStylePosition,
4154 as_list_style_position
4155 );
4156 impl_get_prop!(
4157 get_table_layout,
4158 LayoutTableLayoutValue,
4159 TableLayout,
4160 as_table_layout
4161 );
4162 impl_get_prop!(
4163 get_border_collapse,
4164 StyleBorderCollapseValue,
4165 BorderCollapse,
4166 as_border_collapse
4167 );
4168 impl_get_prop!(
4169 get_border_spacing,
4170 LayoutBorderSpacingValue,
4171 BorderSpacing,
4172 as_border_spacing
4173 );
4174 impl_get_prop!(
4175 get_caption_side,
4176 StyleCaptionSideValue,
4177 CaptionSide,
4178 as_caption_side
4179 );
4180 impl_get_prop!(
4181 get_empty_cells,
4182 StyleEmptyCellsValue,
4183 EmptyCells,
4184 as_empty_cells
4185 );
4186
4187 pub fn calc_width(
4189 &self,
4190 node_data: &NodeData,
4191 node_id: &NodeId,
4192 styled_node_state: &StyledNodeState,
4193 reference_width: f32,
4194 ) -> f32 {
4195 self.get_width(node_data, node_id, styled_node_state)
4196 .and_then(|w| match w.get_property()? {
4197 LayoutWidth::Px(px) => Some(px.to_pixels_internal(
4198 reference_width,
4199 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4200 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4201 )),
4202 _ => Some(0.0), })
4204 .unwrap_or(0.0)
4205 }
4206
4207 pub fn calc_min_width(
4208 &self,
4209 node_data: &NodeData,
4210 node_id: &NodeId,
4211 styled_node_state: &StyledNodeState,
4212 reference_width: f32,
4213 ) -> f32 {
4214 self.get_min_width(node_data, node_id, styled_node_state)
4215 .and_then(|w| {
4216 Some(w.get_property()?.inner.to_pixels_internal(
4217 reference_width,
4218 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4219 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4220 ))
4221 })
4222 .unwrap_or(0.0)
4223 }
4224
4225 pub fn calc_max_width(
4226 &self,
4227 node_data: &NodeData,
4228 node_id: &NodeId,
4229 styled_node_state: &StyledNodeState,
4230 reference_width: f32,
4231 ) -> Option<f32> {
4232 self.get_max_width(node_data, node_id, styled_node_state)
4233 .and_then(|w| {
4234 Some(w.get_property()?.inner.to_pixels_internal(
4235 reference_width,
4236 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4237 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4238 ))
4239 })
4240 }
4241
4242 pub fn calc_height(
4244 &self,
4245 node_data: &NodeData,
4246 node_id: &NodeId,
4247 styled_node_state: &StyledNodeState,
4248 reference_height: f32,
4249 ) -> f32 {
4250 self.get_height(node_data, node_id, styled_node_state)
4251 .and_then(|h| match h.get_property()? {
4252 LayoutHeight::Px(px) => Some(px.to_pixels_internal(
4253 reference_height,
4254 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4255 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4256 )),
4257 _ => Some(0.0), })
4259 .unwrap_or(0.0)
4260 }
4261
4262 pub fn calc_min_height(
4263 &self,
4264 node_data: &NodeData,
4265 node_id: &NodeId,
4266 styled_node_state: &StyledNodeState,
4267 reference_height: f32,
4268 ) -> f32 {
4269 self.get_min_height(node_data, node_id, styled_node_state)
4270 .and_then(|h| {
4271 Some(h.get_property()?.inner.to_pixels_internal(
4272 reference_height,
4273 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4274 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4275 ))
4276 })
4277 .unwrap_or(0.0)
4278 }
4279
4280 pub fn calc_max_height(
4281 &self,
4282 node_data: &NodeData,
4283 node_id: &NodeId,
4284 styled_node_state: &StyledNodeState,
4285 reference_height: f32,
4286 ) -> Option<f32> {
4287 self.get_max_height(node_data, node_id, styled_node_state)
4288 .and_then(|h| {
4289 Some(h.get_property()?.inner.to_pixels_internal(
4290 reference_height,
4291 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4292 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4293 ))
4294 })
4295 }
4296
4297 pub fn calc_left(
4299 &self,
4300 node_data: &NodeData,
4301 node_id: &NodeId,
4302 styled_node_state: &StyledNodeState,
4303 reference_width: f32,
4304 ) -> Option<f32> {
4305 self.get_left(node_data, node_id, styled_node_state)
4306 .and_then(|l| {
4307 Some(l.get_property()?.inner.to_pixels_internal(
4308 reference_width,
4309 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4310 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4311 ))
4312 })
4313 }
4314
4315 pub fn calc_right(
4316 &self,
4317 node_data: &NodeData,
4318 node_id: &NodeId,
4319 styled_node_state: &StyledNodeState,
4320 reference_width: f32,
4321 ) -> Option<f32> {
4322 self.get_right(node_data, node_id, styled_node_state)
4323 .and_then(|r| {
4324 Some(r.get_property()?.inner.to_pixels_internal(
4325 reference_width,
4326 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4327 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4328 ))
4329 })
4330 }
4331
4332 pub fn calc_top(
4333 &self,
4334 node_data: &NodeData,
4335 node_id: &NodeId,
4336 styled_node_state: &StyledNodeState,
4337 reference_height: f32,
4338 ) -> Option<f32> {
4339 self.get_top(node_data, node_id, styled_node_state)
4340 .and_then(|t| {
4341 Some(t.get_property()?.inner.to_pixels_internal(
4342 reference_height,
4343 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4344 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4345 ))
4346 })
4347 }
4348
4349 pub fn calc_bottom(
4350 &self,
4351 node_data: &NodeData,
4352 node_id: &NodeId,
4353 styled_node_state: &StyledNodeState,
4354 reference_height: f32,
4355 ) -> Option<f32> {
4356 self.get_bottom(node_data, node_id, styled_node_state)
4357 .and_then(|b| {
4358 Some(b.get_property()?.inner.to_pixels_internal(
4359 reference_height,
4360 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4361 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4362 ))
4363 })
4364 }
4365
4366 pub fn calc_border_left_width(
4368 &self,
4369 node_data: &NodeData,
4370 node_id: &NodeId,
4371 styled_node_state: &StyledNodeState,
4372 reference_width: f32,
4373 ) -> f32 {
4374 self.get_border_left_width(node_data, node_id, styled_node_state)
4375 .and_then(|b| {
4376 Some(b.get_property()?.inner.to_pixels_internal(
4377 reference_width,
4378 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4379 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4380 ))
4381 })
4382 .unwrap_or(0.0)
4383 }
4384
4385 pub fn calc_border_right_width(
4386 &self,
4387 node_data: &NodeData,
4388 node_id: &NodeId,
4389 styled_node_state: &StyledNodeState,
4390 reference_width: f32,
4391 ) -> f32 {
4392 self.get_border_right_width(node_data, node_id, styled_node_state)
4393 .and_then(|b| {
4394 Some(b.get_property()?.inner.to_pixels_internal(
4395 reference_width,
4396 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4397 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4398 ))
4399 })
4400 .unwrap_or(0.0)
4401 }
4402
4403 pub fn calc_border_top_width(
4404 &self,
4405 node_data: &NodeData,
4406 node_id: &NodeId,
4407 styled_node_state: &StyledNodeState,
4408 reference_height: f32,
4409 ) -> f32 {
4410 self.get_border_top_width(node_data, node_id, styled_node_state)
4411 .and_then(|b| {
4412 Some(b.get_property()?.inner.to_pixels_internal(
4413 reference_height,
4414 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4415 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4416 ))
4417 })
4418 .unwrap_or(0.0)
4419 }
4420
4421 pub fn calc_border_bottom_width(
4422 &self,
4423 node_data: &NodeData,
4424 node_id: &NodeId,
4425 styled_node_state: &StyledNodeState,
4426 reference_height: f32,
4427 ) -> f32 {
4428 self.get_border_bottom_width(node_data, node_id, styled_node_state)
4429 .and_then(|b| {
4430 Some(b.get_property()?.inner.to_pixels_internal(
4431 reference_height,
4432 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4433 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4434 ))
4435 })
4436 .unwrap_or(0.0)
4437 }
4438
4439 pub fn calc_padding_left(
4441 &self,
4442 node_data: &NodeData,
4443 node_id: &NodeId,
4444 styled_node_state: &StyledNodeState,
4445 reference_width: f32,
4446 ) -> f32 {
4447 self.get_padding_left(node_data, node_id, styled_node_state)
4448 .and_then(|p| {
4449 Some(p.get_property()?.inner.to_pixels_internal(
4450 reference_width,
4451 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4452 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4453 ))
4454 })
4455 .unwrap_or(0.0)
4456 }
4457
4458 pub fn calc_padding_right(
4459 &self,
4460 node_data: &NodeData,
4461 node_id: &NodeId,
4462 styled_node_state: &StyledNodeState,
4463 reference_width: f32,
4464 ) -> f32 {
4465 self.get_padding_right(node_data, node_id, styled_node_state)
4466 .and_then(|p| {
4467 Some(p.get_property()?.inner.to_pixels_internal(
4468 reference_width,
4469 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4470 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4471 ))
4472 })
4473 .unwrap_or(0.0)
4474 }
4475
4476 pub fn calc_padding_top(
4477 &self,
4478 node_data: &NodeData,
4479 node_id: &NodeId,
4480 styled_node_state: &StyledNodeState,
4481 reference_height: f32,
4482 ) -> f32 {
4483 self.get_padding_top(node_data, node_id, styled_node_state)
4484 .and_then(|p| {
4485 Some(p.get_property()?.inner.to_pixels_internal(
4486 reference_height,
4487 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4488 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4489 ))
4490 })
4491 .unwrap_or(0.0)
4492 }
4493
4494 pub fn calc_padding_bottom(
4495 &self,
4496 node_data: &NodeData,
4497 node_id: &NodeId,
4498 styled_node_state: &StyledNodeState,
4499 reference_height: f32,
4500 ) -> f32 {
4501 self.get_padding_bottom(node_data, node_id, styled_node_state)
4502 .and_then(|p| {
4503 Some(p.get_property()?.inner.to_pixels_internal(
4504 reference_height,
4505 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4506 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4507 ))
4508 })
4509 .unwrap_or(0.0)
4510 }
4511
4512 pub fn calc_margin_left(
4514 &self,
4515 node_data: &NodeData,
4516 node_id: &NodeId,
4517 styled_node_state: &StyledNodeState,
4518 reference_width: f32,
4519 ) -> f32 {
4520 self.get_margin_left(node_data, node_id, styled_node_state)
4521 .and_then(|m| {
4522 Some(m.get_property()?.inner.to_pixels_internal(
4523 reference_width,
4524 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4525 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4526 ))
4527 })
4528 .unwrap_or(0.0)
4529 }
4530
4531 pub fn calc_margin_right(
4532 &self,
4533 node_data: &NodeData,
4534 node_id: &NodeId,
4535 styled_node_state: &StyledNodeState,
4536 reference_width: f32,
4537 ) -> f32 {
4538 self.get_margin_right(node_data, node_id, styled_node_state)
4539 .and_then(|m| {
4540 Some(m.get_property()?.inner.to_pixels_internal(
4541 reference_width,
4542 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4543 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4544 ))
4545 })
4546 .unwrap_or(0.0)
4547 }
4548
4549 pub fn calc_margin_top(
4550 &self,
4551 node_data: &NodeData,
4552 node_id: &NodeId,
4553 styled_node_state: &StyledNodeState,
4554 reference_height: f32,
4555 ) -> f32 {
4556 self.get_margin_top(node_data, node_id, styled_node_state)
4557 .and_then(|m| {
4558 Some(m.get_property()?.inner.to_pixels_internal(
4559 reference_height,
4560 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4561 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4562 ))
4563 })
4564 .unwrap_or(0.0)
4565 }
4566
4567 pub fn calc_margin_bottom(
4568 &self,
4569 node_data: &NodeData,
4570 node_id: &NodeId,
4571 styled_node_state: &StyledNodeState,
4572 reference_height: f32,
4573 ) -> f32 {
4574 self.get_margin_bottom(node_data, node_id, styled_node_state)
4575 .and_then(|m| {
4576 Some(m.get_property()?.inner.to_pixels_internal(
4577 reference_height,
4578 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4579 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4580 ))
4581 })
4582 .unwrap_or(0.0)
4583 }
4584
4585 #[allow(clippy::too_many_lines)] fn resolve_property_dependency(
4587 target_property: &CssProperty,
4588 reference_property: &CssProperty,
4589 ) -> Option<CssProperty> {
4590 #[allow(clippy::wildcard_imports)]
4593 use azul_css::{
4594 css::CssPropertyValue,
4595 props::{
4596 basic::{font::StyleFontSize, length::SizeMetric, pixel::PixelValue},
4597 layout::*,
4598 style::{SelectionRadius, StyleLetterSpacing, StyleWordSpacing},
4599 },
4600 };
4601
4602 let get_pixel_value = |prop: &CssProperty| -> Option<PixelValue> {
4604 match prop {
4605 CssProperty::FontSize(val) => val.get_property().map(|v| v.inner),
4606 CssProperty::LetterSpacing(val) => val.get_property().map(|v| v.inner),
4607 CssProperty::WordSpacing(val) => val.get_property().map(|v| v.inner),
4608 CssProperty::PaddingLeft(val) => val.get_property().map(|v| v.inner),
4609 CssProperty::PaddingRight(val) => val.get_property().map(|v| v.inner),
4610 CssProperty::PaddingTop(val) => val.get_property().map(|v| v.inner),
4611 CssProperty::PaddingBottom(val) => val.get_property().map(|v| v.inner),
4612 CssProperty::MarginLeft(val) => val.get_property().map(|v| v.inner),
4613 CssProperty::MarginRight(val) => val.get_property().map(|v| v.inner),
4614 CssProperty::MarginTop(val) => val.get_property().map(|v| v.inner),
4615 CssProperty::MarginBottom(val) => val.get_property().map(|v| v.inner),
4616 CssProperty::MinWidth(val) => val.get_property().map(|v| v.inner),
4617 CssProperty::MinHeight(val) => val.get_property().map(|v| v.inner),
4618 CssProperty::MaxWidth(val) => val.get_property().map(|v| v.inner),
4619 CssProperty::MaxHeight(val) => val.get_property().map(|v| v.inner),
4620 CssProperty::SelectionRadius(val) => val.get_property().map(|v| v.inner),
4621 _ => None,
4622 }
4623 };
4624
4625 let target_pixel_value = get_pixel_value(target_property)?;
4626 let reference_pixel_value = get_pixel_value(reference_property)?;
4627
4628 let reference_px = match reference_pixel_value.metric {
4630 SizeMetric::Px => reference_pixel_value.number.get(),
4631 SizeMetric::Pt => reference_pixel_value.number.get() * PT_TO_PX,
4632 SizeMetric::In => reference_pixel_value.number.get() * IN_TO_PX,
4633 SizeMetric::Cm => reference_pixel_value.number.get() * CM_TO_PX,
4634 SizeMetric::Mm => reference_pixel_value.number.get() * MM_TO_PX,
4635 SizeMetric::Em
4637 | SizeMetric::Rem
4638 | SizeMetric::Percent
4639 | SizeMetric::Vw
4640 | SizeMetric::Vh
4641 | SizeMetric::Vmin
4642 | SizeMetric::Vmax => return None,
4643 };
4644
4645 let resolved_px = match target_pixel_value.metric {
4647 SizeMetric::Px => target_pixel_value.number.get(),
4648 SizeMetric::Pt => target_pixel_value.number.get() * PT_TO_PX,
4649 SizeMetric::In => target_pixel_value.number.get() * IN_TO_PX,
4650 SizeMetric::Cm => target_pixel_value.number.get() * CM_TO_PX,
4651 SizeMetric::Mm => target_pixel_value.number.get() * MM_TO_PX,
4652 SizeMetric::Em | SizeMetric::Rem => target_pixel_value.number.get() * reference_px,
4654 SizeMetric::Percent => target_pixel_value.number.get() / 100.0 * reference_px,
4655 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => return None,
4657 };
4658
4659 let resolved_pixel_value = PixelValue::px(resolved_px);
4661
4662 match target_property {
4663 CssProperty::FontSize(_) => Some(CssProperty::FontSize(CssPropertyValue::Exact(
4664 StyleFontSize {
4665 inner: resolved_pixel_value,
4666 },
4667 ))),
4668 CssProperty::LetterSpacing(_) => Some(CssProperty::LetterSpacing(
4669 CssPropertyValue::Exact(StyleLetterSpacing {
4670 inner: resolved_pixel_value,
4671 }),
4672 )),
4673 CssProperty::WordSpacing(_) => Some(CssProperty::WordSpacing(CssPropertyValue::Exact(
4674 StyleWordSpacing {
4675 inner: resolved_pixel_value,
4676 },
4677 ))),
4678 CssProperty::PaddingLeft(_) => Some(CssProperty::PaddingLeft(CssPropertyValue::Exact(
4679 LayoutPaddingLeft {
4680 inner: resolved_pixel_value,
4681 },
4682 ))),
4683 CssProperty::PaddingRight(_) => Some(CssProperty::PaddingRight(
4684 CssPropertyValue::Exact(LayoutPaddingRight {
4685 inner: resolved_pixel_value,
4686 }),
4687 )),
4688 CssProperty::PaddingTop(_) => Some(CssProperty::PaddingTop(CssPropertyValue::Exact(
4689 LayoutPaddingTop {
4690 inner: resolved_pixel_value,
4691 },
4692 ))),
4693 CssProperty::PaddingBottom(_) => Some(CssProperty::PaddingBottom(
4694 CssPropertyValue::Exact(LayoutPaddingBottom {
4695 inner: resolved_pixel_value,
4696 }),
4697 )),
4698 CssProperty::MarginLeft(_) => Some(CssProperty::MarginLeft(CssPropertyValue::Exact(
4699 LayoutMarginLeft {
4700 inner: resolved_pixel_value,
4701 },
4702 ))),
4703 CssProperty::MarginRight(_) => Some(CssProperty::MarginRight(CssPropertyValue::Exact(
4704 LayoutMarginRight {
4705 inner: resolved_pixel_value,
4706 },
4707 ))),
4708 CssProperty::MarginTop(_) => Some(CssProperty::MarginTop(CssPropertyValue::Exact(
4709 LayoutMarginTop {
4710 inner: resolved_pixel_value,
4711 },
4712 ))),
4713 CssProperty::MarginBottom(_) => Some(CssProperty::MarginBottom(
4714 CssPropertyValue::Exact(LayoutMarginBottom {
4715 inner: resolved_pixel_value,
4716 }),
4717 )),
4718 CssProperty::MinWidth(_) => Some(CssProperty::MinWidth(CssPropertyValue::Exact(
4719 LayoutMinWidth {
4720 inner: resolved_pixel_value,
4721 },
4722 ))),
4723 CssProperty::MinHeight(_) => Some(CssProperty::MinHeight(CssPropertyValue::Exact(
4724 LayoutMinHeight {
4725 inner: resolved_pixel_value,
4726 },
4727 ))),
4728 CssProperty::MaxWidth(_) => Some(CssProperty::MaxWidth(CssPropertyValue::Exact(
4729 LayoutMaxWidth {
4730 inner: resolved_pixel_value,
4731 },
4732 ))),
4733 CssProperty::MaxHeight(_) => Some(CssProperty::MaxHeight(CssPropertyValue::Exact(
4734 LayoutMaxHeight {
4735 inner: resolved_pixel_value,
4736 },
4737 ))),
4738 CssProperty::SelectionRadius(_) => Some(CssProperty::SelectionRadius(
4739 CssPropertyValue::Exact(SelectionRadius {
4740 inner: resolved_pixel_value,
4741 }),
4742 )),
4743 _ => None,
4744 }
4745 }
4746
4747 #[allow(clippy::too_many_lines)] pub fn apply_ua_css(&mut self, node_data: &[NodeData]) {
4758 use azul_css::dynamic_selector::PseudoStateType;
4759 use azul_css::props::property::CssPropertyType;
4760
4761 let node_count = node_data.len();
4762 if node_count == 0 {
4763 return;
4764 }
4765
4766 let mut prop_set: Vec<[u128; 2]> = vec![[0u128; 2]; node_count];
4769
4770 for (node_idx, props) in self.css_props.iter_node_slices() {
4772 for p in props {
4773 if p.state == PseudoStateType::Normal {
4774 let d = p.prop_type as u16 as usize;
4775 if d < 128 {
4776 prop_set[node_idx][0] |= 1u128 << d;
4777 } else {
4778 prop_set[node_idx][1] |= 1u128 << (d - 128);
4779 }
4780 }
4781 }
4782 }
4783
4784 for (node_idx, props) in self.cascaded_props.iter_node_slices() {
4786 for p in props {
4787 if p.state == PseudoStateType::Normal {
4788 let d = p.prop_type as u16 as usize;
4789 if d < 128 {
4790 prop_set[node_idx][0] |= 1u128 << d;
4791 } else {
4792 prop_set[node_idx][1] |= 1u128 << (d - 128);
4793 }
4794 }
4795 }
4796 }
4797
4798 for (node_idx, node) in node_data.iter().enumerate() {
4800 for (prop, conds) in node.style.iter_inline_properties() {
4801 let is_normal = conds.as_slice().is_empty();
4802 if is_normal {
4803 let d = prop.get_type() as u16 as usize;
4804 if d < 128 {
4805 prop_set[node_idx][0] |= 1u128 << d;
4806 } else {
4807 prop_set[node_idx][1] |= 1u128 << (d - 128);
4808 }
4809 }
4810 }
4811 }
4812
4813 if !self.global_css_props.is_empty() {
4822 let mut global_bits = [0u128; 2];
4823 for p in &self.global_css_props {
4824 let d = p.get_type() as u16 as usize;
4825 if d < 128 {
4826 global_bits[0] |= 1u128 << d;
4827 } else {
4828 global_bits[1] |= 1u128 << (d - 128);
4829 }
4830 }
4831 for (node_idx, node) in node_data.iter().enumerate() {
4832 if !node.is_text_node() {
4833 prop_set[node_idx][0] |= global_bits[0];
4834 prop_set[node_idx][1] |= global_bits[1];
4835 }
4836 }
4837 }
4838
4839 let property_types = [
4845 CssPropertyType::Display,
4846 CssPropertyType::OverflowX,
4847 CssPropertyType::OverflowY,
4848 CssPropertyType::Width,
4849 CssPropertyType::Height,
4850 CssPropertyType::FontSize,
4851 CssPropertyType::FontWeight,
4852 CssPropertyType::FontFamily,
4853 CssPropertyType::MarginTop,
4854 CssPropertyType::MarginBottom,
4855 CssPropertyType::MarginLeft,
4856 CssPropertyType::MarginRight,
4857 CssPropertyType::PaddingTop,
4858 CssPropertyType::PaddingBottom,
4859 CssPropertyType::PaddingLeft,
4860 CssPropertyType::PaddingRight,
4861 CssPropertyType::BorderTopStyle,
4862 CssPropertyType::BorderTopWidth,
4863 CssPropertyType::BorderTopColor,
4864 CssPropertyType::BreakInside,
4865 CssPropertyType::BreakAfter,
4866 CssPropertyType::ListStyleType,
4867 CssPropertyType::CounterReset,
4868 CssPropertyType::TextDecoration,
4869 CssPropertyType::TextAlign,
4870 CssPropertyType::VerticalAlign,
4871 CssPropertyType::Cursor,
4872 ];
4873
4874 for (node_index, node) in node_data.iter().enumerate() {
4876 let node_type = &node.node_type;
4877
4878 for prop_type in &property_types {
4879 let d = *prop_type as u16 as usize;
4881 let has_prop = if d < 128 {
4882 (prop_set[node_index][0] & (1u128 << d)) != 0
4883 } else {
4884 (prop_set[node_index][1] & (1u128 << (d - 128))) != 0
4885 };
4886
4887 if has_prop {
4888 continue;
4889 }
4890
4891 if let Some(ua_prop) = crate::ua_css::get_ua_property(node_type, *prop_type) {
4893 self.cascaded_props.push_to(
4894 node_index,
4895 StatefulCssProperty {
4896 state: PseudoStateType::Normal,
4897 prop_type: *prop_type,
4898 property: ua_prop.clone(),
4899 },
4900 );
4901
4902 if d < 128 {
4904 prop_set[node_index][0] |= 1u128 << d;
4905 } else {
4906 prop_set[node_index][1] |= 1u128 << (d - 128);
4907 }
4908 }
4909 }
4910 }
4911 }
4912
4913 pub fn sort_cascaded_props(&mut self) {
4916 self.cascaded_props
4917 .sort_each_and_flatten(|p| (p.state, p.prop_type));
4918 }
4919
4920 pub fn compute_inherited_values(
4926 &mut self,
4927 node_hierarchy: &[NodeHierarchyItem],
4928 node_data: &[NodeData],
4929 ) -> Vec<NodeId> {
4930 self.computed_values.grow_to(node_hierarchy.len());
4931 let previous = core::mem::replace(&mut self.computed_values, InheritedValues::new());
4936 self.computed_values.grow_to(node_hierarchy.len());
4937 node_hierarchy
4938 .iter()
4939 .enumerate()
4940 .filter_map(|(node_index, hierarchy_item)| {
4941 let node_id = NodeId::new(node_index);
4942 let parent_id = hierarchy_item.parent_id();
4943 let parent_computed: Option<Vec<(CssPropertyType, CssPropertyWithOrigin)>> =
4947 parent_id.map(|pid| self.computed_values.values_for(pid.index()));
4948
4949 let mut ctx = InheritanceContext {
4950 node_id,
4951 parent_id,
4952 computed_values: Vec::new(),
4953 };
4954
4955 if let Some(ref parent_values) = parent_computed {
4957 Self::inherit_from_parent(&mut ctx, parent_values);
4958 }
4959
4960 self.apply_cascade_properties(
4962 &mut ctx,
4963 node_id,
4964 parent_computed.as_ref(),
4965 node_data,
4966 node_index,
4967 );
4968
4969 let changed = self.store_if_changed(&ctx, &previous);
4971 changed.then_some(node_id)
4972 })
4973 .collect()
4974 }
4975
4976 fn inherit_from_parent(
4978 ctx: &mut InheritanceContext,
4979 parent_values: &[(CssPropertyType, CssPropertyWithOrigin)],
4980 ) {
4981 for (prop_type, prop_with_origin) in
4982 parent_values.iter().filter(|(pt, _)| pt.is_inheritable())
4983 {
4984 let entry = (
4985 *prop_type,
4986 CssPropertyWithOrigin {
4987 property: prop_with_origin.property.clone(),
4988 origin: CssPropertyOrigin::Inherited,
4989 },
4990 );
4991 match ctx
4993 .computed_values
4994 .binary_search_by_key(prop_type, |(k, _)| *k)
4995 {
4996 Ok(idx) => ctx.computed_values[idx] = entry,
4997 Err(idx) => ctx.computed_values.insert(idx, entry),
4998 }
4999 }
5000 }
5001
5002 fn apply_cascade_properties(
5004 &self,
5005 ctx: &mut InheritanceContext,
5006 node_id: NodeId,
5007 parent_computed: Option<&Vec<(CssPropertyType, CssPropertyWithOrigin)>>,
5008 node_data: &[NodeData],
5009 node_index: usize,
5010 ) {
5011 {
5013 let cascaded_slice = self.cascaded_props.get_slice(node_id.index());
5014 for p in cascaded_slice {
5015 if p.state == azul_css::dynamic_selector::PseudoStateType::Normal
5016 && Self::should_apply_cascaded(&ctx.computed_values, p.prop_type, &p.property)
5017 {
5018 Self::process_property(ctx, &p.property, parent_computed);
5019 }
5020 }
5021 }
5022
5023 {
5025 let css_slice = self.css_props.get_slice(node_id.index());
5026 for p in css_slice {
5027 if p.state == azul_css::dynamic_selector::PseudoStateType::Normal {
5028 Self::process_property(ctx, &p.property, parent_computed);
5029 }
5030 }
5031 }
5032
5033 for (prop, conds) in node_data[node_index].style.iter_inline_properties() {
5035 if conds.as_slice().is_empty() {
5037 Self::process_property(ctx, prop, parent_computed);
5038 }
5039 }
5040
5041 if let Some(user_props) = self.user_overridden_properties.get(node_id.index()) {
5043 for (_, prop) in user_props {
5044 Self::process_property(ctx, prop, parent_computed);
5045 }
5046 }
5047 }
5048
5049 fn should_apply_cascaded(
5062 computed: &[(CssPropertyType, CssPropertyWithOrigin)],
5063 prop_type: CssPropertyType,
5064 _prop: &CssProperty,
5065 ) -> bool {
5066 computed
5067 .binary_search_by_key(&prop_type, |(k, _)| *k)
5068 .map_or(true, |idx| {
5069 computed[idx].1.origin == CssPropertyOrigin::Inherited
5070 })
5071 }
5072
5073 fn process_property(
5075 ctx: &mut InheritanceContext,
5076 prop: &CssProperty,
5077 parent_computed: Option<&Vec<(CssPropertyType, CssPropertyWithOrigin)>>,
5078 ) {
5079 let prop_type = prop.get_type();
5080
5081 let resolved = if prop_type == CssPropertyType::FontSize {
5082 Self::resolve_font_size_property(prop, parent_computed)
5083 } else {
5084 Self::resolve_other_property(prop, &ctx.computed_values)
5085 };
5086
5087 let entry = (
5088 prop_type,
5089 CssPropertyWithOrigin {
5090 property: resolved,
5091 origin: CssPropertyOrigin::Own,
5092 },
5093 );
5094 match ctx
5095 .computed_values
5096 .binary_search_by_key(&prop_type, |(k, _)| *k)
5097 {
5098 Ok(idx) => ctx.computed_values[idx] = entry,
5099 Err(idx) => ctx.computed_values.insert(idx, entry),
5100 }
5101 }
5102
5103 fn resolve_font_size_property(
5105 prop: &CssProperty,
5106 parent_computed: Option<&Vec<(CssPropertyType, CssPropertyWithOrigin)>>,
5107 ) -> CssProperty {
5108 let parent_font_size = parent_computed.and_then(|p| {
5109 p.binary_search_by_key(&CssPropertyType::FontSize, |(k, _)| *k)
5110 .ok()
5111 .map(|idx| &p[idx].1)
5112 });
5113
5114 parent_font_size.map_or_else(
5115 || {
5116 Self::resolve_font_size_to_pixels(
5117 prop,
5118 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
5119 )
5120 },
5121 |pfs| {
5122 Self::resolve_property_dependency(prop, &pfs.property).unwrap_or_else(|| {
5123 Self::resolve_font_size_to_pixels(
5124 prop,
5125 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
5126 )
5127 })
5128 },
5129 )
5130 }
5131
5132 fn resolve_other_property(
5134 prop: &CssProperty,
5135 computed: &[(CssPropertyType, CssPropertyWithOrigin)],
5136 ) -> CssProperty {
5137 computed
5138 .binary_search_by_key(&CssPropertyType::FontSize, |(k, _)| *k)
5139 .ok()
5140 .and_then(|idx| Self::resolve_property_dependency(prop, &computed[idx].1.property))
5141 .unwrap_or_else(|| prop.clone())
5142 }
5143
5144 fn resolve_font_size_to_pixels(prop: &CssProperty, reference_px: f32) -> CssProperty {
5146 use azul_css::{
5147 css::CssPropertyValue,
5148 props::basic::{font::StyleFontSize, length::SizeMetric, pixel::PixelValue},
5149 };
5150
5151 let CssProperty::FontSize(css_val) = prop else {
5152 return prop.clone();
5153 };
5154
5155 let Some(font_size) = css_val.get_property() else {
5156 return prop.clone();
5157 };
5158
5159 let resolved_px = match font_size.inner.metric {
5160 SizeMetric::Px => font_size.inner.number.get(),
5161 SizeMetric::Pt => font_size.inner.number.get() * PT_TO_PX,
5162 SizeMetric::In => font_size.inner.number.get() * IN_TO_PX,
5163 SizeMetric::Cm => font_size.inner.number.get() * CM_TO_PX,
5164 SizeMetric::Mm => font_size.inner.number.get() * MM_TO_PX,
5165 SizeMetric::Em => font_size.inner.number.get() * reference_px,
5166 SizeMetric::Rem => {
5167 font_size.inner.number.get() * azul_css::props::basic::pixel::DEFAULT_FONT_SIZE
5168 }
5169 SizeMetric::Percent => font_size.inner.number.get() / 100.0 * reference_px,
5170 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => {
5171 return prop.clone();
5172 }
5173 };
5174
5175 CssProperty::FontSize(CssPropertyValue::Exact(StyleFontSize {
5176 inner: PixelValue::px(resolved_px),
5177 }))
5178 }
5179
5180 fn has_relative_font_size_unit(prop: &CssProperty) -> bool {
5182 use azul_css::props::basic::length::SizeMetric;
5183
5184 let CssProperty::FontSize(css_val) = prop else {
5185 return false;
5186 };
5187
5188 css_val.get_property().is_some_and(|fs| {
5189 matches!(
5190 fs.inner.metric,
5191 SizeMetric::Em | SizeMetric::Rem | SizeMetric::Percent
5192 )
5193 })
5194 }
5195
5196 fn store_if_changed(
5217 &mut self,
5218 ctx: &InheritanceContext,
5219 previous: &InheritedValues,
5220 ) -> bool {
5221 let inheritable: Vec<(CssPropertyType, CssPropertyWithOrigin)> = ctx
5222 .computed_values
5223 .iter()
5224 .filter(|(pt, _)| pt.is_inheritable())
5225 .cloned()
5226 .collect();
5227 let changed = previous.values_for(ctx.node_id.index()) != inheritable;
5228 self.computed_values.set_node(ctx.node_id.index(), &inheritable);
5229 changed
5230 }
5231}
5232
5233struct InheritanceContext {
5235 node_id: NodeId,
5236 parent_id: Option<NodeId>,
5237 computed_values: Vec<(CssPropertyType, CssPropertyWithOrigin)>,
5238}
5239
5240impl CssPropertyCache {
5241 pub(crate) fn invalidate_resolved_cache(&mut self) {
5243 self.compact_cache = None;
5244 }
5245}
5246
5247#[cfg(test)]
5248#[path = "prop_cache_test.rs"]
5249mod prop_cache_test;