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