1extern crate alloc;
25
26use alloc::{boxed::Box, collections::BTreeMap, 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
47#[derive(Debug, Clone, PartialEq)]
50pub enum CssDependencyChainStep {
51 Percent { source_node: NodeId, factor: f32 },
54
55 Em { source_node: NodeId, factor: f32 },
58
59 Rem { factor: f32 },
62
63 Absolute { pixels: f32 },
65}
66
67#[derive(Debug, Clone, PartialEq)]
75pub struct CssDependencyChain {
76 pub property_type: CssPropertyType,
78
79 pub steps: Vec<CssDependencyChainStep>,
82
83 pub cached_pixels: Option<f32>,
86}
87
88impl CssDependencyChain {
89 pub fn absolute(property_type: CssPropertyType, pixels: f32) -> Self {
91 Self {
92 property_type,
93 steps: vec![CssDependencyChainStep::Absolute { pixels }],
94 cached_pixels: Some(pixels),
95 }
96 }
97
98 pub fn percent(property_type: CssPropertyType, source_node: NodeId, factor: f32) -> Self {
100 Self {
101 property_type,
102 steps: vec![CssDependencyChainStep::Percent {
103 source_node,
104 factor,
105 }],
106 cached_pixels: None,
107 }
108 }
109
110 pub fn em(property_type: CssPropertyType, source_node: NodeId, factor: f32) -> Self {
112 Self {
113 property_type,
114 steps: vec![CssDependencyChainStep::Em {
115 source_node,
116 factor,
117 }],
118 cached_pixels: None,
119 }
120 }
121
122 pub fn rem(property_type: CssPropertyType, factor: f32) -> Self {
124 Self {
125 property_type,
126 steps: vec![CssDependencyChainStep::Rem { factor }],
127 cached_pixels: None,
128 }
129 }
130
131 pub fn depends_on(&self, node_id: NodeId) -> bool {
133 self.steps.iter().any(|step| match step {
134 CssDependencyChainStep::Percent { source_node, .. } => *source_node == node_id,
135 CssDependencyChainStep::Em { source_node, .. } => *source_node == node_id,
136 _ => false,
137 })
138 }
139
140 pub fn resolve<F>(&mut self, mut resolve_node_value: F, root_font_size: f32) -> Option<f32>
149 where
150 F: FnMut(NodeId, CssPropertyType) -> Option<f32>,
151 {
152 let mut current_value: Option<f32> = None;
153
154 for step in &self.steps {
155 match step {
156 CssDependencyChainStep::Absolute { pixels } => {
157 current_value = Some(*pixels);
158 }
159 CssDependencyChainStep::Percent {
160 source_node,
161 factor,
162 } => {
163 let source_val = resolve_node_value(*source_node, self.property_type)?;
164 current_value = Some(source_val * factor);
165 }
166 CssDependencyChainStep::Em {
167 source_node,
168 factor,
169 } => {
170 let font_size = resolve_node_value(*source_node, CssPropertyType::FontSize)?;
171 current_value = Some(font_size * factor);
172 }
173 CssDependencyChainStep::Rem { factor } => {
174 current_value = Some(root_font_size * factor);
175 }
176 }
177 }
178
179 self.cached_pixels = current_value;
180 current_value
181 }
182}
183
184use azul_css::{
185 css::{Css, CssPath},
186 props::{
187 basic::{StyleFontFamily, StyleFontFamilyVec, StyleFontSize},
188 layout::{LayoutDisplay, LayoutHeight, LayoutWidth},
189 property::{
190 BoxDecorationBreakValue, BreakInsideValue, CaretAnimationDurationValue,
191 CaretColorValue, CaretWidthValue, ClipPathValue, ColumnCountValue, ColumnFillValue,
192 ColumnRuleColorValue, ColumnRuleStyleValue, ColumnRuleWidthValue, ColumnSpanValue,
193 ColumnWidthValue, ContentValue, CounterIncrementValue, CounterResetValue, CssProperty,
194 CssPropertyType, FlowFromValue, FlowIntoValue, LayoutAlignContentValue,
195 LayoutAlignItemsValue, LayoutAlignSelfValue, LayoutBorderBottomWidthValue,
196 LayoutBorderLeftWidthValue, LayoutBorderRightWidthValue, LayoutBorderSpacingValue,
197 LayoutBorderTopWidthValue, LayoutBoxSizingValue, LayoutClearValue,
198 LayoutColumnGapValue, LayoutDisplayValue, LayoutFlexBasisValue,
199 LayoutFlexDirectionValue, LayoutFlexGrowValue, LayoutFlexShrinkValue,
200 LayoutFlexWrapValue, LayoutFloatValue, LayoutGapValue, LayoutGridAutoColumnsValue,
201 LayoutGridAutoFlowValue, LayoutGridAutoRowsValue, LayoutGridColumnValue,
202 LayoutGridRowValue, LayoutGridTemplateColumnsValue, LayoutGridTemplateRowsValue,
203 LayoutHeightValue, LayoutInsetBottomValue, LayoutJustifyContentValue,
204 LayoutJustifyItemsValue, LayoutJustifySelfValue, LayoutLeftValue,
205 LayoutMarginBottomValue, LayoutMarginLeftValue, LayoutMarginRightValue,
206 LayoutMarginTopValue, LayoutMaxHeightValue, LayoutMaxWidthValue, LayoutMinHeightValue,
207 LayoutMinWidthValue, LayoutOverflowValue, LayoutPaddingBottomValue,
208 LayoutPaddingLeftValue, LayoutPaddingRightValue, LayoutPaddingTopValue,
209 LayoutPositionValue, LayoutRightValue, LayoutRowGapValue, LayoutScrollbarWidthValue,
210 LayoutTableLayoutValue, LayoutTextJustifyValue, LayoutTopValue, LayoutWidthValue,
211 LayoutWritingModeValue, LayoutZIndexValue, OrphansValue, PageBreakValue,
212 ScrollbarStyleValue, SelectionBackgroundColorValue, SelectionColorValue,
213 SelectionRadiusValue, ShapeImageThresholdValue, ShapeInsideValue, ShapeMarginValue,
214 ShapeOutsideValue, StringSetValue, StyleBackfaceVisibilityValue,
215 StyleBackgroundContentVecValue, StyleBackgroundPositionVecValue,
216 StyleBackgroundRepeatVecValue, StyleBackgroundSizeVecValue,
217 StyleBorderBottomColorValue, StyleBorderBottomLeftRadiusValue,
218 StyleBorderBottomRightRadiusValue, StyleBorderBottomStyleValue,
219 StyleBorderCollapseValue, StyleBorderLeftColorValue, StyleBorderLeftStyleValue,
220 StyleBorderRightColorValue, StyleBorderRightStyleValue, StyleBorderTopColorValue,
221 StyleBorderTopLeftRadiusValue, StyleBorderTopRightRadiusValue,
222 StyleBorderTopStyleValue, StyleBoxShadowValue, StyleCaptionSideValue, StyleCursorValue,
223 StyleDirectionValue, StyleEmptyCellsValue, StyleExclusionMarginValue,
224 StyleFilterVecValue, StyleFontFamilyVecValue, StyleFontSizeValue, StyleFontStyleValue,
225 StyleFontValue, StyleFontWeightValue, StyleHangingPunctuationValue,
226 StyleHyphenationLanguageValue, StyleHyphensValue, StyleInitialLetterValue,
227 StyleLetterSpacingValue, StyleLineClampValue, StyleLineHeightValue,
228 StyleListStylePositionValue, StyleListStyleTypeValue, StyleMixBlendModeValue,
229 StyleOpacityValue, StylePerspectiveOriginValue, StyleScrollbarColorValue,
230 StyleTabWidthValue, StyleTextAlignValue, StyleTextColorValue,
231 StyleTextCombineUprightValue, StyleTextDecorationValue, StyleTextIndentValue,
232 StyleTransformOriginValue, StyleTransformVecValue, StyleUserSelectValue,
233 StyleVerticalAlignValue, StyleVisibilityValue, StyleWhiteSpaceValue,
234 StyleWordSpacingValue, WidowsValue,
235 },
236 style::{StyleCursor, StyleTextColor, StyleTransformOrigin},
237 },
238 AzString,
239};
240
241use crate::{
242 dom::{NodeData, NodeId, TabIndex, TagId},
243 id::{NodeDataContainer, NodeDataContainerRef},
244 style::CascadeInfo,
245 styled_dom::{
246 NodeHierarchyItem, NodeHierarchyItemId, NodeHierarchyItemVec, ParentWithNodeDepth,
247 ParentWithNodeDepthVec, StyledNodeState, TagIdToNodeIdMapping,
248 },
249};
250
251use azul_css::dynamic_selector::{
252 CssPropertyWithConditions, CssPropertyWithConditionsVec, DynamicSelectorContext,
253};
254
255macro_rules! match_property_value {
258 ($property:expr, $value:ident, $expr:expr) => {
259 match $property {
260 CssProperty::CaretColor($value) => $expr,
261 CssProperty::CaretAnimationDuration($value) => $expr,
262 CssProperty::SelectionBackgroundColor($value) => $expr,
263 CssProperty::SelectionColor($value) => $expr,
264 CssProperty::SelectionRadius($value) => $expr,
265 CssProperty::TextColor($value) => $expr,
266 CssProperty::FontSize($value) => $expr,
267 CssProperty::FontFamily($value) => $expr,
268 CssProperty::FontWeight($value) => $expr,
269 CssProperty::FontStyle($value) => $expr,
270 CssProperty::TextAlign($value) => $expr,
271 CssProperty::TextJustify($value) => $expr,
272 CssProperty::VerticalAlign($value) => $expr,
273 CssProperty::LetterSpacing($value) => $expr,
274 CssProperty::TextIndent($value) => $expr,
275 CssProperty::InitialLetter($value) => $expr,
276 CssProperty::LineClamp($value) => $expr,
277 CssProperty::HangingPunctuation($value) => $expr,
278 CssProperty::TextCombineUpright($value) => $expr,
279 CssProperty::ExclusionMargin($value) => $expr,
280 CssProperty::HyphenationLanguage($value) => $expr,
281 CssProperty::LineHeight($value) => $expr,
282 CssProperty::WordSpacing($value) => $expr,
283 CssProperty::TabWidth($value) => $expr,
284 CssProperty::WhiteSpace($value) => $expr,
285 CssProperty::Hyphens($value) => $expr,
286 CssProperty::Direction($value) => $expr,
287 CssProperty::UserSelect($value) => $expr,
288 CssProperty::TextDecoration($value) => $expr,
289 CssProperty::Cursor($value) => $expr,
290 CssProperty::Display($value) => $expr,
291 CssProperty::Float($value) => $expr,
292 CssProperty::BoxSizing($value) => $expr,
293 CssProperty::Width($value) => $expr,
294 CssProperty::Height($value) => $expr,
295 CssProperty::MinWidth($value) => $expr,
296 CssProperty::MinHeight($value) => $expr,
297 CssProperty::MaxWidth($value) => $expr,
298 CssProperty::MaxHeight($value) => $expr,
299 CssProperty::Position($value) => $expr,
300 CssProperty::Top($value) => $expr,
301 CssProperty::Right($value) => $expr,
302 CssProperty::Left($value) => $expr,
303 CssProperty::Bottom($value) => $expr,
304 CssProperty::ZIndex($value) => $expr,
305 CssProperty::FlexWrap($value) => $expr,
306 CssProperty::FlexDirection($value) => $expr,
307 CssProperty::FlexGrow($value) => $expr,
308 CssProperty::FlexShrink($value) => $expr,
309 CssProperty::FlexBasis($value) => $expr,
310 CssProperty::JustifyContent($value) => $expr,
311 CssProperty::AlignItems($value) => $expr,
312 CssProperty::AlignContent($value) => $expr,
313 CssProperty::AlignSelf($value) => $expr,
314 CssProperty::JustifyItems($value) => $expr,
315 CssProperty::JustifySelf($value) => $expr,
316 CssProperty::BackgroundContent($value) => $expr,
317 CssProperty::BackgroundPosition($value) => $expr,
318 CssProperty::BackgroundSize($value) => $expr,
319 CssProperty::BackgroundRepeat($value) => $expr,
320 CssProperty::OverflowX($value) => $expr,
321 CssProperty::OverflowY($value) => $expr,
322 CssProperty::PaddingTop($value) => $expr,
323 CssProperty::PaddingLeft($value) => $expr,
324 CssProperty::PaddingRight($value) => $expr,
325 CssProperty::PaddingBottom($value) => $expr,
326 CssProperty::MarginTop($value) => $expr,
327 CssProperty::MarginLeft($value) => $expr,
328 CssProperty::MarginRight($value) => $expr,
329 CssProperty::MarginBottom($value) => $expr,
330 CssProperty::BorderTopLeftRadius($value) => $expr,
331 CssProperty::BorderTopRightRadius($value) => $expr,
332 CssProperty::BorderBottomLeftRadius($value) => $expr,
333 CssProperty::BorderBottomRightRadius($value) => $expr,
334 CssProperty::BorderTopColor($value) => $expr,
335 CssProperty::BorderRightColor($value) => $expr,
336 CssProperty::BorderLeftColor($value) => $expr,
337 CssProperty::BorderBottomColor($value) => $expr,
338 CssProperty::BorderTopStyle($value) => $expr,
339 CssProperty::BorderRightStyle($value) => $expr,
340 CssProperty::BorderLeftStyle($value) => $expr,
341 CssProperty::BorderBottomStyle($value) => $expr,
342 CssProperty::BorderTopWidth($value) => $expr,
343 CssProperty::BorderRightWidth($value) => $expr,
344 CssProperty::BorderLeftWidth($value) => $expr,
345 CssProperty::BorderBottomWidth($value) => $expr,
346 CssProperty::BoxShadow($value) => $expr,
347 CssProperty::Opacity($value) => $expr,
348 CssProperty::Transform($value) => $expr,
349 CssProperty::TransformOrigin($value) => $expr,
350 CssProperty::PerspectiveOrigin($value) => $expr,
351 CssProperty::BackfaceVisibility($value) => $expr,
352 CssProperty::MixBlendMode($value) => $expr,
353 CssProperty::Filter($value) => $expr,
354 CssProperty::Visibility($value) => $expr,
355 CssProperty::WritingMode($value) => $expr,
356 CssProperty::GridTemplateColumns($value) => $expr,
357 CssProperty::GridTemplateRows($value) => $expr,
358 CssProperty::GridAutoColumns($value) => $expr,
359 CssProperty::GridAutoRows($value) => $expr,
360 CssProperty::GridAutoFlow($value) => $expr,
361 CssProperty::GridColumn($value) => $expr,
362 CssProperty::GridRow($value) => $expr,
363 CssProperty::Gap($value) => $expr,
364 CssProperty::ColumnGap($value) => $expr,
365 CssProperty::RowGap($value) => $expr,
366 CssProperty::Clear($value) => $expr,
367 CssProperty::ScrollbarStyle($value) => $expr,
368 CssProperty::ScrollbarWidth($value) => $expr,
369 CssProperty::ScrollbarColor($value) => $expr,
370 CssProperty::ListStyleType($value) => $expr,
371 CssProperty::ListStylePosition($value) => $expr,
372 CssProperty::Font($value) => $expr,
373 CssProperty::ColumnCount($value) => $expr,
374 CssProperty::ColumnWidth($value) => $expr,
375 CssProperty::ColumnSpan($value) => $expr,
376 CssProperty::ColumnFill($value) => $expr,
377 CssProperty::ColumnRuleStyle($value) => $expr,
378 CssProperty::ColumnRuleWidth($value) => $expr,
379 CssProperty::ColumnRuleColor($value) => $expr,
380 CssProperty::FlowInto($value) => $expr,
381 CssProperty::FlowFrom($value) => $expr,
382 CssProperty::ShapeOutside($value) => $expr,
383 CssProperty::ShapeInside($value) => $expr,
384 CssProperty::ShapeImageThreshold($value) => $expr,
385 CssProperty::ShapeMargin($value) => $expr,
386 CssProperty::ClipPath($value) => $expr,
387 CssProperty::Content($value) => $expr,
388 CssProperty::CounterIncrement($value) => $expr,
389 CssProperty::CounterReset($value) => $expr,
390 CssProperty::StringSet($value) => $expr,
391 CssProperty::Orphans($value) => $expr,
392 CssProperty::Widows($value) => $expr,
393 CssProperty::PageBreakBefore($value) => $expr,
394 CssProperty::PageBreakAfter($value) => $expr,
395 CssProperty::PageBreakInside($value) => $expr,
396 CssProperty::BreakInside($value) => $expr,
397 CssProperty::BoxDecorationBreak($value) => $expr,
398 CssProperty::TableLayout($value) => $expr,
399 CssProperty::BorderCollapse($value) => $expr,
400 CssProperty::BorderSpacing($value) => $expr,
401 CssProperty::CaptionSide($value) => $expr,
402 CssProperty::EmptyCells($value) => $expr,
403 }
404 };
405}
406
407fn get_initial_value(property_type: CssPropertyType) -> Option<CssProperty> {
410 use azul_css::css::CssPropertyValue;
411
412 match property_type {
415 _ => None,
418 }
419}
420
421#[derive(Debug, Default, Clone, PartialEq)]
433pub struct CssPropertyCache {
434 pub node_count: usize,
436
437 pub user_overridden_properties: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
439
440 pub cascaded_normal_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
442 pub cascaded_hover_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
443 pub cascaded_active_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
444 pub cascaded_focus_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
445
446 pub css_normal_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
448 pub css_hover_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
449 pub css_active_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
450 pub css_focus_props: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssProperty>>,
451
452 pub computed_values: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
459
460 pub dependency_chains: BTreeMap<NodeId, BTreeMap<CssPropertyType, CssDependencyChain>>,
471}
472
473impl CssPropertyCache {
474 #[must_use]
476 pub fn restyle(
477 &mut self,
478 css: &mut Css,
479 node_data: &NodeDataContainerRef<NodeData>,
480 node_hierarchy: &NodeHierarchyItemVec,
481 non_leaf_nodes: &ParentWithNodeDepthVec,
482 html_tree: &NodeDataContainerRef<CascadeInfo>,
483 ) -> Vec<TagIdToNodeIdMapping> {
484 use azul_css::{
485 css::{CssDeclaration, CssPathPseudoSelector::*},
486 props::layout::LayoutDisplay,
487 };
488
489 let css_is_empty = css.is_empty();
490
491 if !css_is_empty {
492 css.sort_by_specificity();
493
494 macro_rules! filter_rules {($expected_pseudo_selector:expr, $node_id:expr) => {{
495 css
496 .rules() .filter(|rule_block| crate::style::rule_ends_with(&rule_block.path, $expected_pseudo_selector))
498 .filter(|rule_block| crate::style::matches_html_element(
499 &rule_block.path,
500 $node_id,
501 &node_hierarchy.as_container(),
502 &node_data,
503 &html_tree,
504 $expected_pseudo_selector
505 ))
506 .flat_map(|matched_rule| {
508 matched_rule.declarations
509 .iter()
510 .filter_map(move |declaration| {
511 match declaration {
512 CssDeclaration::Static(s) => Some(s),
513 CssDeclaration::Dynamic(_d) => None, }
515 })
516 })
517 .map(|prop| prop.clone())
518 .collect::<Vec<CssProperty>>()
519 }};}
520
521 let css_normal_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
531 .transform_nodeid_multithreaded_optional(|node_id| {
532 let r = filter_rules!(None, node_id);
533 if r.is_empty() {
534 None
535 } else {
536 Some((node_id, r))
537 }
538 });
539
540 let css_hover_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
541 .transform_nodeid_multithreaded_optional(|node_id| {
542 let r = filter_rules!(Some(Hover), node_id);
543 if r.is_empty() {
544 None
545 } else {
546 Some((node_id, r))
547 }
548 });
549
550 let css_active_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
551 .transform_nodeid_multithreaded_optional(|node_id| {
552 let r = filter_rules!(Some(Active), node_id);
553 if r.is_empty() {
554 None
555 } else {
556 Some((node_id, r))
557 }
558 });
559
560 let css_focus_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
561 .transform_nodeid_multithreaded_optional(|node_id| {
562 let r = filter_rules!(Some(Focus), node_id);
563 if r.is_empty() {
564 None
565 } else {
566 Some((node_id, r))
567 }
568 });
569
570 self.css_normal_props = css_normal_rules
571 .internal
572 .into_iter()
573 .map(|(n, map)| {
574 (
575 n,
576 map.into_iter()
577 .map(|prop| (prop.get_type(), prop))
578 .collect(),
579 )
580 })
581 .collect();
582
583 self.css_hover_props = css_hover_rules
584 .internal
585 .into_iter()
586 .map(|(n, map)| {
587 (
588 n,
589 map.into_iter()
590 .map(|prop| (prop.get_type(), prop))
591 .collect(),
592 )
593 })
594 .collect();
595
596 self.css_active_props = css_active_rules
597 .internal
598 .into_iter()
599 .map(|(n, map)| {
600 (
601 n,
602 map.into_iter()
603 .map(|prop| (prop.get_type(), prop))
604 .collect(),
605 )
606 })
607 .collect();
608
609 self.css_focus_props = css_focus_rules
610 .internal
611 .into_iter()
612 .map(|(n, map)| {
613 (
614 n,
615 map.into_iter()
616 .map(|prop| (prop.get_type(), prop))
617 .collect(),
618 )
619 })
620 .collect();
621 }
622
623 for ParentWithNodeDepth { depth: _, node_id } in non_leaf_nodes.iter() {
626 let parent_id = match node_id.into_crate_internal() {
627 Some(s) => s,
628 None => continue,
629 };
630
631 macro_rules! inherit_props {
634 ($from_inherit_map:expr, $to_inherit_map:expr) => {
635 let parent_inheritable_css_props =
636 $from_inherit_map.get(&parent_id).and_then(|map| {
637 let parent_inherit_props = map
638 .iter()
639 .filter(|(css_prop_type, _)| css_prop_type.is_inheritable())
640 .map(|(css_prop_type, css_prop)| (*css_prop_type, css_prop.clone()))
641 .collect::<Vec<(CssPropertyType, CssProperty)>>();
642 if parent_inherit_props.is_empty() {
643 None
644 } else {
645 Some(parent_inherit_props)
646 }
647 });
648
649 match parent_inheritable_css_props {
650 Some(pi) => {
651 for child_id in parent_id.az_children(&node_hierarchy.as_container()) {
654 let child_map = $to_inherit_map
655 .entry(child_id)
656 .or_insert_with(|| BTreeMap::new());
657
658 for (inherited_rule_type, inherited_rule_value) in pi.iter() {
659 let _ = child_map
660 .entry(*inherited_rule_type)
661 .or_insert_with(|| inherited_rule_value.clone());
662 }
663 }
664 }
665 None => {}
666 }
667 };
668 }
669
670 macro_rules! inherit_inline_css_props {($filter_pseudo_state:expr, $to_inherit_map:expr) => {{
673 let parent_inheritable_css_props = &node_data[parent_id]
674 .css_props
675 .iter()
676 .filter(|css_prop| {
678 let conditions = css_prop.apply_if.as_slice();
680 if conditions.is_empty() {
681 $filter_pseudo_state == PseudoStateType::Normal
683 } else {
684 conditions.iter().all(|c| {
686 matches!(c, DynamicSelector::PseudoState(state) if *state == $filter_pseudo_state)
687 })
688 }
689 })
690 .map(|css_prop| &css_prop.property)
692 .filter(|css_prop| css_prop.get_type().is_inheritable())
694 .cloned()
695 .collect::<Vec<CssProperty>>();
696
697 if !parent_inheritable_css_props.is_empty() {
698 for child_id in parent_id.az_children(&node_hierarchy.as_container()) {
700 let child_map = $to_inherit_map.entry(child_id).or_insert_with(|| BTreeMap::new());
701 for inherited_rule in parent_inheritable_css_props.iter() {
702 let _ = child_map
703 .entry(inherited_rule.get_type())
704 .or_insert_with(|| inherited_rule.clone());
705 }
706 }
707 }
708
709 }};}
710
711 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
712 inherit_inline_css_props!(PseudoStateType::Normal, self.cascaded_normal_props);
716 inherit_inline_css_props!(PseudoStateType::Hover, self.cascaded_hover_props);
717 inherit_inline_css_props!(PseudoStateType::Active, self.cascaded_active_props);
718 inherit_inline_css_props!(PseudoStateType::Focus, self.cascaded_focus_props);
719
720 if !css_is_empty {
722 inherit_props!(self.css_normal_props, self.cascaded_normal_props);
723 inherit_props!(self.css_hover_props, self.cascaded_hover_props);
724 inherit_props!(self.css_active_props, self.cascaded_active_props);
725 inherit_props!(self.css_focus_props, self.cascaded_focus_props);
726 }
727
728 inherit_props!(self.cascaded_normal_props, self.cascaded_normal_props);
730 inherit_props!(self.cascaded_hover_props, self.cascaded_hover_props);
731 inherit_props!(self.cascaded_active_props, self.cascaded_active_props);
732 inherit_props!(self.cascaded_focus_props, self.cascaded_focus_props);
733 }
734
735 let default_node_state = StyledNodeState::default();
738
739 let node_data_container = &node_data.internal;
750
751 node_data
752 .internal
753 .iter()
754 .enumerate()
755 .filter_map(|(node_id, node_data)| {
756 let node_id = NodeId::new(node_id);
757
758 let should_auto_insert_tabindex = node_data
759 .get_callbacks()
760 .iter()
761 .any(|cb| cb.event.is_focus_callback());
762
763 let tab_index = match node_data.get_tab_index() {
764 Some(s) => Some(*s),
765 None => {
766 if should_auto_insert_tabindex {
767 Some(TabIndex::Auto)
768 } else {
769 None
770 }
771 }
772 };
773
774 let mut node_should_have_tag = false;
775
776 loop {
779 let display = self
781 .get_display(&node_data, &node_id, &default_node_state)
782 .and_then(|p| p.get_property_or_default())
783 .unwrap_or_default();
784
785 if display == LayoutDisplay::None {
786 node_should_have_tag = false;
787 break;
788 }
789
790 if node_data.has_context_menu() {
791 node_should_have_tag = true;
792 break;
793 }
794
795 if tab_index.is_some() {
796 node_should_have_tag = true;
797 break;
798 }
799
800 if node_data.get_context_menu().is_some() {
802 node_should_have_tag = true;
803 break;
804 }
805
806 let node_has_hover_props = {
808 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
809 node_data.css_props.as_ref().iter().any(|p| {
810 p.apply_if.as_slice().iter().any(|c| {
811 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Hover))
812 })
813 })
814 } || self.css_hover_props.get(&node_id).is_some()
815 || self.cascaded_hover_props.get(&node_id).is_some();
816
817 if node_has_hover_props {
818 node_should_have_tag = true;
819 break;
820 }
821
822 let node_has_active_props = {
824 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
825 node_data.css_props.as_ref().iter().any(|p| {
826 p.apply_if.as_slice().iter().any(|c| {
827 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Active))
828 })
829 })
830 } || self.css_active_props.get(&node_id).is_some()
831 || self.cascaded_active_props.get(&node_id).is_some();
832
833 if node_has_active_props {
834 node_should_have_tag = true;
835 break;
836 }
837
838 let node_has_focus_props = {
840 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
841 node_data.css_props.as_ref().iter().any(|p| {
842 p.apply_if.as_slice().iter().any(|c| {
843 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Focus))
844 })
845 })
846 } || self.css_focus_props.get(&node_id).is_some()
847 || self.cascaded_focus_props.get(&node_id).is_some();
848
849 if node_has_focus_props {
850 node_should_have_tag = true;
851 break;
852 }
853
854 let node_only_window_callbacks = node_data.get_callbacks().is_empty()
856 || node_data
857 .get_callbacks()
858 .iter()
859 .all(|cb| cb.event.is_window_callback());
860
861 if !node_only_window_callbacks {
862 node_should_have_tag = true;
863 break;
864 }
865
866 let node_has_non_default_cursor = self
868 .get_cursor(&node_data, &node_id, &default_node_state)
869 .is_some();
870
871 if node_has_non_default_cursor {
872 node_should_have_tag = true;
873 break;
874 }
875
876 let node_has_overflow_scroll = {
880 use azul_css::props::layout::LayoutOverflow;
881 let overflow_x = self
882 .get_overflow_x(&node_data, &node_id, &default_node_state)
883 .and_then(|p| p.get_property_or_default());
884 let overflow_y = self
885 .get_overflow_y(&node_data, &node_id, &default_node_state)
886 .and_then(|p| p.get_property_or_default());
887
888 let x_scrollable = matches!(
889 overflow_x,
890 Some(LayoutOverflow::Scroll | LayoutOverflow::Auto)
891 );
892 let y_scrollable = matches!(
893 overflow_y,
894 Some(LayoutOverflow::Scroll | LayoutOverflow::Auto)
895 );
896 x_scrollable || y_scrollable
897 };
898
899 if node_has_overflow_scroll {
900 node_should_have_tag = true;
901 break;
902 }
903
904 let node_has_selectable_text = {
910 use azul_css::props::style::StyleUserSelect;
911 use crate::dom::NodeType;
912
913 let has_text_children = {
915 let hier = node_hierarchy.as_container()[node_id];
916 let mut has_text = false;
917 if let Some(first_child) = hier.first_child_id(node_id) {
918 let mut child_id = Some(first_child);
919 while let Some(cid) = child_id {
920 let child_data = &node_data_container[cid.index()];
921 if matches!(child_data.get_node_type(), NodeType::Text(_)) {
922 has_text = true;
923 break;
924 }
925 child_id = node_hierarchy.as_container()[cid].next_sibling_id();
926 }
927 }
928 has_text
929 };
930
931 if has_text_children {
932 let user_select = self
934 .get_user_select(&node_data, &node_id, &default_node_state)
935 .and_then(|p| p.get_property().cloned())
936 .unwrap_or(StyleUserSelect::Auto);
937
938 !matches!(user_select, StyleUserSelect::None)
939 } else {
940 false
941 }
942 };
943
944 if node_has_selectable_text {
945 node_should_have_tag = true;
946 break;
947 }
948
949 break;
950 }
951
952 if !node_should_have_tag {
953 None
954 } else {
955 Some(TagIdToNodeIdMapping {
956 tag_id: TagId::from_crate_internal(TagId::unique()),
957 node_id: NodeHierarchyItemId::from_crate_internal(Some(node_id)),
958 tab_index: tab_index.into(),
959 parent_node_ids: {
960 let mut parents = Vec::new();
961 let mut cur_parent = node_hierarchy.as_container()[node_id].parent_id();
962 while let Some(c) = cur_parent.clone() {
963 parents.push(NodeHierarchyItemId::from_crate_internal(Some(c)));
964 cur_parent = node_hierarchy.as_container()[c].parent_id();
965 }
966 parents.reverse(); parents.into()
968 },
969 })
970 }
971 })
972 .collect()
973 }
974
975 pub fn get_computed_css_style_string(
976 &self,
977 node_data: &NodeData,
978 node_id: &NodeId,
979 node_state: &StyledNodeState,
980 ) -> String {
981 let mut s = String::new();
982 if let Some(p) = self.get_background_content(&node_data, node_id, node_state) {
983 s.push_str(&format!("background: {};", p.get_css_value_fmt()));
984 }
985 if let Some(p) = self.get_background_position(&node_data, node_id, node_state) {
986 s.push_str(&format!("background-position: {};", p.get_css_value_fmt()));
987 }
988 if let Some(p) = self.get_background_size(&node_data, node_id, node_state) {
989 s.push_str(&format!("background-size: {};", p.get_css_value_fmt()));
990 }
991 if let Some(p) = self.get_background_repeat(&node_data, node_id, node_state) {
992 s.push_str(&format!("background-repeat: {};", p.get_css_value_fmt()));
993 }
994 if let Some(p) = self.get_font_size(&node_data, node_id, node_state) {
995 s.push_str(&format!("font-size: {};", p.get_css_value_fmt()));
996 }
997 if let Some(p) = self.get_font_family(&node_data, node_id, node_state) {
998 s.push_str(&format!("font-family: {};", p.get_css_value_fmt()));
999 }
1000 if let Some(p) = self.get_text_color(&node_data, node_id, node_state) {
1001 s.push_str(&format!("color: {};", p.get_css_value_fmt()));
1002 }
1003 if let Some(p) = self.get_text_align(&node_data, node_id, node_state) {
1004 s.push_str(&format!("text-align: {};", p.get_css_value_fmt()));
1005 }
1006 if let Some(p) = self.get_line_height(&node_data, node_id, node_state) {
1007 s.push_str(&format!("line-height: {};", p.get_css_value_fmt()));
1008 }
1009 if let Some(p) = self.get_letter_spacing(&node_data, node_id, node_state) {
1010 s.push_str(&format!("letter-spacing: {};", p.get_css_value_fmt()));
1011 }
1012 if let Some(p) = self.get_word_spacing(&node_data, node_id, node_state) {
1013 s.push_str(&format!("word-spacing: {};", p.get_css_value_fmt()));
1014 }
1015 if let Some(p) = self.get_tab_width(&node_data, node_id, node_state) {
1016 s.push_str(&format!("tab-width: {};", p.get_css_value_fmt()));
1017 }
1018 if let Some(p) = self.get_cursor(&node_data, node_id, node_state) {
1019 s.push_str(&format!("cursor: {};", p.get_css_value_fmt()));
1020 }
1021 if let Some(p) = self.get_box_shadow_left(&node_data, node_id, node_state) {
1022 s.push_str(&format!(
1023 "-azul-box-shadow-left: {};",
1024 p.get_css_value_fmt()
1025 ));
1026 }
1027 if let Some(p) = self.get_box_shadow_right(&node_data, node_id, node_state) {
1028 s.push_str(&format!(
1029 "-azul-box-shadow-right: {};",
1030 p.get_css_value_fmt()
1031 ));
1032 }
1033 if let Some(p) = self.get_box_shadow_top(&node_data, node_id, node_state) {
1034 s.push_str(&format!("-azul-box-shadow-top: {};", p.get_css_value_fmt()));
1035 }
1036 if let Some(p) = self.get_box_shadow_bottom(&node_data, node_id, node_state) {
1037 s.push_str(&format!(
1038 "-azul-box-shadow-bottom: {};",
1039 p.get_css_value_fmt()
1040 ));
1041 }
1042 if let Some(p) = self.get_border_top_color(&node_data, node_id, node_state) {
1043 s.push_str(&format!("border-top-color: {};", p.get_css_value_fmt()));
1044 }
1045 if let Some(p) = self.get_border_left_color(&node_data, node_id, node_state) {
1046 s.push_str(&format!("border-left-color: {};", p.get_css_value_fmt()));
1047 }
1048 if let Some(p) = self.get_border_right_color(&node_data, node_id, node_state) {
1049 s.push_str(&format!("border-right-color: {};", p.get_css_value_fmt()));
1050 }
1051 if let Some(p) = self.get_border_bottom_color(&node_data, node_id, node_state) {
1052 s.push_str(&format!("border-bottom-color: {};", p.get_css_value_fmt()));
1053 }
1054 if let Some(p) = self.get_border_top_style(&node_data, node_id, node_state) {
1055 s.push_str(&format!("border-top-style: {};", p.get_css_value_fmt()));
1056 }
1057 if let Some(p) = self.get_border_left_style(&node_data, node_id, node_state) {
1058 s.push_str(&format!("border-left-style: {};", p.get_css_value_fmt()));
1059 }
1060 if let Some(p) = self.get_border_right_style(&node_data, node_id, node_state) {
1061 s.push_str(&format!("border-right-style: {};", p.get_css_value_fmt()));
1062 }
1063 if let Some(p) = self.get_border_bottom_style(&node_data, node_id, node_state) {
1064 s.push_str(&format!("border-bottom-style: {};", p.get_css_value_fmt()));
1065 }
1066 if let Some(p) = self.get_border_top_left_radius(&node_data, node_id, node_state) {
1067 s.push_str(&format!(
1068 "border-top-left-radius: {};",
1069 p.get_css_value_fmt()
1070 ));
1071 }
1072 if let Some(p) = self.get_border_top_right_radius(&node_data, node_id, node_state) {
1073 s.push_str(&format!(
1074 "border-top-right-radius: {};",
1075 p.get_css_value_fmt()
1076 ));
1077 }
1078 if let Some(p) = self.get_border_bottom_left_radius(&node_data, node_id, node_state) {
1079 s.push_str(&format!(
1080 "border-bottom-left-radius: {};",
1081 p.get_css_value_fmt()
1082 ));
1083 }
1084 if let Some(p) = self.get_border_bottom_right_radius(&node_data, node_id, node_state) {
1085 s.push_str(&format!(
1086 "border-bottom-right-radius: {};",
1087 p.get_css_value_fmt()
1088 ));
1089 }
1090 if let Some(p) = self.get_opacity(&node_data, node_id, node_state) {
1091 s.push_str(&format!("opacity: {};", p.get_css_value_fmt()));
1092 }
1093 if let Some(p) = self.get_transform(&node_data, node_id, node_state) {
1094 s.push_str(&format!("transform: {};", p.get_css_value_fmt()));
1095 }
1096 if let Some(p) = self.get_transform_origin(&node_data, node_id, node_state) {
1097 s.push_str(&format!("transform-origin: {};", p.get_css_value_fmt()));
1098 }
1099 if let Some(p) = self.get_perspective_origin(&node_data, node_id, node_state) {
1100 s.push_str(&format!("perspective-origin: {};", p.get_css_value_fmt()));
1101 }
1102 if let Some(p) = self.get_backface_visibility(&node_data, node_id, node_state) {
1103 s.push_str(&format!("backface-visibility: {};", p.get_css_value_fmt()));
1104 }
1105 if let Some(p) = self.get_hyphens(&node_data, node_id, node_state) {
1106 s.push_str(&format!("hyphens: {};", p.get_css_value_fmt()));
1107 }
1108 if let Some(p) = self.get_direction(&node_data, node_id, node_state) {
1109 s.push_str(&format!("direction: {};", p.get_css_value_fmt()));
1110 }
1111 if let Some(p) = self.get_white_space(&node_data, node_id, node_state) {
1112 s.push_str(&format!("white-space: {};", p.get_css_value_fmt()));
1113 }
1114 if let Some(p) = self.get_display(&node_data, node_id, node_state) {
1115 s.push_str(&format!("display: {};", p.get_css_value_fmt()));
1116 }
1117 if let Some(p) = self.get_float(&node_data, node_id, node_state) {
1118 s.push_str(&format!("float: {};", p.get_css_value_fmt()));
1119 }
1120 if let Some(p) = self.get_box_sizing(&node_data, node_id, node_state) {
1121 s.push_str(&format!("box-sizing: {};", p.get_css_value_fmt()));
1122 }
1123 if let Some(p) = self.get_width(&node_data, node_id, node_state) {
1124 s.push_str(&format!("width: {};", p.get_css_value_fmt()));
1125 }
1126 if let Some(p) = self.get_height(&node_data, node_id, node_state) {
1127 s.push_str(&format!("height: {};", p.get_css_value_fmt()));
1128 }
1129 if let Some(p) = self.get_min_width(&node_data, node_id, node_state) {
1130 s.push_str(&format!("min-width: {};", p.get_css_value_fmt()));
1131 }
1132 if let Some(p) = self.get_min_height(&node_data, node_id, node_state) {
1133 s.push_str(&format!("min-height: {};", p.get_css_value_fmt()));
1134 }
1135 if let Some(p) = self.get_max_width(&node_data, node_id, node_state) {
1136 s.push_str(&format!("max-width: {};", p.get_css_value_fmt()));
1137 }
1138 if let Some(p) = self.get_max_height(&node_data, node_id, node_state) {
1139 s.push_str(&format!("max-height: {};", p.get_css_value_fmt()));
1140 }
1141 if let Some(p) = self.get_position(&node_data, node_id, node_state) {
1142 s.push_str(&format!("position: {};", p.get_css_value_fmt()));
1143 }
1144 if let Some(p) = self.get_top(&node_data, node_id, node_state) {
1145 s.push_str(&format!("top: {};", p.get_css_value_fmt()));
1146 }
1147 if let Some(p) = self.get_bottom(&node_data, node_id, node_state) {
1148 s.push_str(&format!("bottom: {};", p.get_css_value_fmt()));
1149 }
1150 if let Some(p) = self.get_right(&node_data, node_id, node_state) {
1151 s.push_str(&format!("right: {};", p.get_css_value_fmt()));
1152 }
1153 if let Some(p) = self.get_left(&node_data, node_id, node_state) {
1154 s.push_str(&format!("left: {};", p.get_css_value_fmt()));
1155 }
1156 if let Some(p) = self.get_padding_top(&node_data, node_id, node_state) {
1157 s.push_str(&format!("padding-top: {};", p.get_css_value_fmt()));
1158 }
1159 if let Some(p) = self.get_padding_bottom(&node_data, node_id, node_state) {
1160 s.push_str(&format!("padding-bottom: {};", p.get_css_value_fmt()));
1161 }
1162 if let Some(p) = self.get_padding_left(&node_data, node_id, node_state) {
1163 s.push_str(&format!("padding-left: {};", p.get_css_value_fmt()));
1164 }
1165 if let Some(p) = self.get_padding_right(&node_data, node_id, node_state) {
1166 s.push_str(&format!("padding-right: {};", p.get_css_value_fmt()));
1167 }
1168 if let Some(p) = self.get_margin_top(&node_data, node_id, node_state) {
1169 s.push_str(&format!("margin-top: {};", p.get_css_value_fmt()));
1170 }
1171 if let Some(p) = self.get_margin_bottom(&node_data, node_id, node_state) {
1172 s.push_str(&format!("margin-bottom: {};", p.get_css_value_fmt()));
1173 }
1174 if let Some(p) = self.get_margin_left(&node_data, node_id, node_state) {
1175 s.push_str(&format!("margin-left: {};", p.get_css_value_fmt()));
1176 }
1177 if let Some(p) = self.get_margin_right(&node_data, node_id, node_state) {
1178 s.push_str(&format!("margin-right: {};", p.get_css_value_fmt()));
1179 }
1180 if let Some(p) = self.get_border_top_width(&node_data, node_id, node_state) {
1181 s.push_str(&format!("border-top-width: {};", p.get_css_value_fmt()));
1182 }
1183 if let Some(p) = self.get_border_left_width(&node_data, node_id, node_state) {
1184 s.push_str(&format!("border-left-width: {};", p.get_css_value_fmt()));
1185 }
1186 if let Some(p) = self.get_border_right_width(&node_data, node_id, node_state) {
1187 s.push_str(&format!("border-right-width: {};", p.get_css_value_fmt()));
1188 }
1189 if let Some(p) = self.get_border_bottom_width(&node_data, node_id, node_state) {
1190 s.push_str(&format!("border-bottom-width: {};", p.get_css_value_fmt()));
1191 }
1192 if let Some(p) = self.get_overflow_x(&node_data, node_id, node_state) {
1193 s.push_str(&format!("overflow-x: {};", p.get_css_value_fmt()));
1194 }
1195 if let Some(p) = self.get_overflow_y(&node_data, node_id, node_state) {
1196 s.push_str(&format!("overflow-y: {};", p.get_css_value_fmt()));
1197 }
1198 if let Some(p) = self.get_flex_direction(&node_data, node_id, node_state) {
1199 s.push_str(&format!("flex-direction: {};", p.get_css_value_fmt()));
1200 }
1201 if let Some(p) = self.get_flex_wrap(&node_data, node_id, node_state) {
1202 s.push_str(&format!("flex-wrap: {};", p.get_css_value_fmt()));
1203 }
1204 if let Some(p) = self.get_flex_grow(&node_data, node_id, node_state) {
1205 s.push_str(&format!("flex-grow: {};", p.get_css_value_fmt()));
1206 }
1207 if let Some(p) = self.get_flex_shrink(&node_data, node_id, node_state) {
1208 s.push_str(&format!("flex-shrink: {};", p.get_css_value_fmt()));
1209 }
1210 if let Some(p) = self.get_justify_content(&node_data, node_id, node_state) {
1211 s.push_str(&format!("justify-content: {};", p.get_css_value_fmt()));
1212 }
1213 if let Some(p) = self.get_align_items(&node_data, node_id, node_state) {
1214 s.push_str(&format!("align-items: {};", p.get_css_value_fmt()));
1215 }
1216 if let Some(p) = self.get_align_content(&node_data, node_id, node_state) {
1217 s.push_str(&format!("align-content: {};", p.get_css_value_fmt()));
1218 }
1219 s
1220 }
1221}
1222
1223#[repr(C)]
1224#[derive(Debug, PartialEq, Clone)]
1225pub struct CssPropertyCachePtr {
1226 pub ptr: Box<CssPropertyCache>,
1227 pub run_destructor: bool,
1228}
1229
1230impl CssPropertyCachePtr {
1231 pub fn new(cache: CssPropertyCache) -> Self {
1232 Self {
1233 ptr: Box::new(cache),
1234 run_destructor: true,
1235 }
1236 }
1237 pub fn downcast_mut<'a>(&'a mut self) -> &'a mut CssPropertyCache {
1238 &mut *self.ptr
1239 }
1240}
1241
1242impl Drop for CssPropertyCachePtr {
1243 fn drop(&mut self) {
1244 self.run_destructor = false;
1245 }
1246}
1247
1248impl CssPropertyCache {
1249 pub fn empty(node_count: usize) -> Self {
1250 Self {
1251 node_count,
1252 user_overridden_properties: BTreeMap::new(),
1253
1254 cascaded_normal_props: BTreeMap::new(),
1255 cascaded_hover_props: BTreeMap::new(),
1256 cascaded_active_props: BTreeMap::new(),
1257 cascaded_focus_props: BTreeMap::new(),
1258
1259 css_normal_props: BTreeMap::new(),
1260 css_hover_props: BTreeMap::new(),
1261 css_active_props: BTreeMap::new(),
1262 css_focus_props: BTreeMap::new(),
1263
1264 computed_values: BTreeMap::new(),
1265 dependency_chains: BTreeMap::new(),
1266 }
1267 }
1268
1269 pub fn append(&mut self, other: &mut Self) {
1270 macro_rules! append_css_property_vec {
1271 ($field_name:ident) => {{
1272 let mut s = BTreeMap::new();
1273 core::mem::swap(&mut s, &mut other.$field_name);
1274 for (node_id, property_map) in s.into_iter() {
1275 self.$field_name
1276 .insert(node_id + self.node_count, property_map);
1277 }
1278 }};
1279 }
1280
1281 append_css_property_vec!(user_overridden_properties);
1282 append_css_property_vec!(cascaded_normal_props);
1283 append_css_property_vec!(cascaded_hover_props);
1284 append_css_property_vec!(cascaded_active_props);
1285 append_css_property_vec!(cascaded_focus_props);
1286 append_css_property_vec!(css_normal_props);
1287 append_css_property_vec!(css_hover_props);
1288 append_css_property_vec!(css_active_props);
1289 append_css_property_vec!(css_focus_props);
1290 append_css_property_vec!(computed_values);
1291
1292 {
1294 let mut s = BTreeMap::new();
1295 core::mem::swap(&mut s, &mut other.dependency_chains);
1296 for (node_id, mut chains_map) in s.into_iter() {
1297 for (_prop_type, chain) in chains_map.iter_mut() {
1299 for step in chain.steps.iter_mut() {
1300 match step {
1301 CssDependencyChainStep::Em { source_node, .. } => {
1302 *source_node = NodeId::new(source_node.index() + self.node_count);
1303 }
1304 CssDependencyChainStep::Percent { source_node, .. } => {
1305 *source_node = NodeId::new(source_node.index() + self.node_count);
1306 }
1307 _ => {}
1308 }
1309 }
1310 }
1311 self.dependency_chains
1312 .insert(node_id + self.node_count, chains_map);
1313 }
1314 }
1315
1316 self.node_count += other.node_count;
1317 }
1318
1319 pub fn is_horizontal_overflow_visible(
1320 &self,
1321 node_data: &NodeData,
1322 node_id: &NodeId,
1323 node_state: &StyledNodeState,
1324 ) -> bool {
1325 self.get_overflow_x(node_data, node_id, node_state)
1326 .and_then(|p| p.get_property_or_default())
1327 .unwrap_or_default()
1328 .is_overflow_visible()
1329 }
1330
1331 pub fn is_vertical_overflow_visible(
1332 &self,
1333 node_data: &NodeData,
1334 node_id: &NodeId,
1335 node_state: &StyledNodeState,
1336 ) -> bool {
1337 self.get_overflow_y(node_data, node_id, node_state)
1338 .and_then(|p| p.get_property_or_default())
1339 .unwrap_or_default()
1340 .is_overflow_visible()
1341 }
1342
1343 pub fn is_horizontal_overflow_hidden(
1344 &self,
1345 node_data: &NodeData,
1346 node_id: &NodeId,
1347 node_state: &StyledNodeState,
1348 ) -> bool {
1349 self.get_overflow_x(node_data, node_id, node_state)
1350 .and_then(|p| p.get_property_or_default())
1351 .unwrap_or_default()
1352 .is_overflow_hidden()
1353 }
1354
1355 pub fn is_vertical_overflow_hidden(
1356 &self,
1357 node_data: &NodeData,
1358 node_id: &NodeId,
1359 node_state: &StyledNodeState,
1360 ) -> bool {
1361 self.get_overflow_y(node_data, node_id, node_state)
1362 .and_then(|p| p.get_property_or_default())
1363 .unwrap_or_default()
1364 .is_overflow_hidden()
1365 }
1366
1367 pub fn get_text_color_or_default(
1368 &self,
1369 node_data: &NodeData,
1370 node_id: &NodeId,
1371 node_state: &StyledNodeState,
1372 ) -> StyleTextColor {
1373 use crate::ui_solver::DEFAULT_TEXT_COLOR;
1374 self.get_text_color(node_data, node_id, node_state)
1375 .and_then(|fs| fs.get_property().cloned())
1376 .unwrap_or(DEFAULT_TEXT_COLOR)
1377 }
1378
1379 pub fn get_font_id_or_default(
1381 &self,
1382 node_data: &NodeData,
1383 node_id: &NodeId,
1384 node_state: &StyledNodeState,
1385 ) -> StyleFontFamilyVec {
1386 use crate::ui_solver::DEFAULT_FONT_ID;
1387 let default_font_id = vec![StyleFontFamily::System(AzString::from_const_str(
1388 DEFAULT_FONT_ID,
1389 ))]
1390 .into();
1391 let font_family_opt = self.get_font_family(node_data, node_id, node_state);
1392
1393 font_family_opt
1394 .as_ref()
1395 .and_then(|family| Some(family.get_property()?.clone()))
1396 .unwrap_or(default_font_id)
1397 }
1398
1399 pub fn get_font_size_or_default(
1400 &self,
1401 node_data: &NodeData,
1402 node_id: &NodeId,
1403 node_state: &StyledNodeState,
1404 ) -> StyleFontSize {
1405 use crate::ui_solver::DEFAULT_FONT_SIZE;
1406 self.get_font_size(node_data, node_id, node_state)
1407 .and_then(|fs| fs.get_property().cloned())
1408 .unwrap_or(DEFAULT_FONT_SIZE)
1409 }
1410
1411 pub fn has_border(
1412 &self,
1413 node_data: &NodeData,
1414 node_id: &NodeId,
1415 node_state: &StyledNodeState,
1416 ) -> bool {
1417 self.get_border_left_width(node_data, node_id, node_state)
1418 .is_some()
1419 || self
1420 .get_border_right_width(node_data, node_id, node_state)
1421 .is_some()
1422 || self
1423 .get_border_top_width(node_data, node_id, node_state)
1424 .is_some()
1425 || self
1426 .get_border_bottom_width(node_data, node_id, node_state)
1427 .is_some()
1428 }
1429
1430 pub fn has_box_shadow(
1431 &self,
1432 node_data: &NodeData,
1433 node_id: &NodeId,
1434 node_state: &StyledNodeState,
1435 ) -> bool {
1436 self.get_box_shadow_left(node_data, node_id, node_state)
1437 .is_some()
1438 || self
1439 .get_box_shadow_right(node_data, node_id, node_state)
1440 .is_some()
1441 || self
1442 .get_box_shadow_top(node_data, node_id, node_state)
1443 .is_some()
1444 || self
1445 .get_box_shadow_bottom(node_data, node_id, node_state)
1446 .is_some()
1447 }
1448
1449 pub fn get_property<'a>(
1450 &'a self,
1451 node_data: &'a NodeData,
1452 node_id: &NodeId,
1453 node_state: &StyledNodeState,
1454 css_property_type: &CssPropertyType,
1455 ) -> Option<&CssProperty> {
1456 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
1460
1461 if let Some(p) = self
1463 .user_overridden_properties
1464 .get(node_id)
1465 .and_then(|n| n.get(css_property_type))
1466 {
1467 return Some(p);
1468 }
1469
1470 fn matches_pseudo_state(
1472 prop: &azul_css::dynamic_selector::CssPropertyWithConditions,
1473 state: PseudoStateType,
1474 ) -> bool {
1475 let conditions = prop.apply_if.as_slice();
1476 if conditions.is_empty() {
1477 state == PseudoStateType::Normal
1478 } else {
1479 conditions
1480 .iter()
1481 .all(|c| matches!(c, DynamicSelector::PseudoState(s) if *s == state))
1482 }
1483 }
1484
1485 if node_state.focused {
1488 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1490 if matches_pseudo_state(css_prop, PseudoStateType::Focus)
1491 && css_prop.property.get_type() == *css_property_type
1492 {
1493 Some(&css_prop.property)
1494 } else {
1495 None
1496 }
1497 }) {
1498 return Some(p);
1499 }
1500
1501 if let Some(p) = self
1503 .css_focus_props
1504 .get(node_id)
1505 .and_then(|map| map.get(css_property_type))
1506 {
1507 return Some(p);
1508 }
1509
1510 if let Some(p) = self
1512 .cascaded_focus_props
1513 .get(node_id)
1514 .and_then(|map| map.get(css_property_type))
1515 {
1516 return Some(p);
1517 }
1518 }
1519
1520 if node_state.active {
1521 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1523 if matches_pseudo_state(css_prop, PseudoStateType::Active)
1524 && css_prop.property.get_type() == *css_property_type
1525 {
1526 Some(&css_prop.property)
1527 } else {
1528 None
1529 }
1530 }) {
1531 return Some(p);
1532 }
1533
1534 if let Some(p) = self
1536 .css_active_props
1537 .get(node_id)
1538 .and_then(|map| map.get(css_property_type))
1539 {
1540 return Some(p);
1541 }
1542
1543 if let Some(p) = self
1545 .cascaded_active_props
1546 .get(node_id)
1547 .and_then(|map| map.get(css_property_type))
1548 {
1549 return Some(p);
1550 }
1551 }
1552
1553 if node_state.hover {
1554 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1556 if matches_pseudo_state(css_prop, PseudoStateType::Hover)
1557 && css_prop.property.get_type() == *css_property_type
1558 {
1559 Some(&css_prop.property)
1560 } else {
1561 None
1562 }
1563 }) {
1564 return Some(p);
1565 }
1566
1567 if let Some(p) = self
1569 .css_hover_props
1570 .get(node_id)
1571 .and_then(|map| map.get(css_property_type))
1572 {
1573 return Some(p);
1574 }
1575
1576 if let Some(p) = self
1578 .cascaded_hover_props
1579 .get(node_id)
1580 .and_then(|map| map.get(css_property_type))
1581 {
1582 return Some(p);
1583 }
1584 }
1585
1586 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1589 if matches_pseudo_state(css_prop, PseudoStateType::Normal)
1590 && css_prop.property.get_type() == *css_property_type
1591 {
1592 Some(&css_prop.property)
1593 } else {
1594 None
1595 }
1596 }) {
1597 return Some(p);
1598 }
1599
1600 if let Some(p) = self
1602 .css_normal_props
1603 .get(node_id)
1604 .and_then(|map| map.get(css_property_type))
1605 {
1606 return Some(p);
1607 }
1608
1609 if let Some(p) = self
1611 .cascaded_normal_props
1612 .get(node_id)
1613 .and_then(|map| map.get(css_property_type))
1614 {
1615 return Some(p);
1616 }
1617
1618 if css_property_type.is_inheritable() {
1622 if let Some(prop_with_origin) = self
1623 .computed_values
1624 .get(node_id)
1625 .and_then(|map| map.get(css_property_type))
1626 {
1627 return Some(&prop_with_origin.property);
1628 }
1629 }
1630
1631 crate::ua_css::get_ua_property(&node_data.node_type, *css_property_type)
1634 }
1635
1636 pub fn get_property_with_context<'a>(
1644 &'a self,
1645 node_data: &'a NodeData,
1646 node_id: &NodeId,
1647 context: &DynamicSelectorContext,
1648 css_property_type: &CssPropertyType,
1649 ) -> Option<&CssProperty> {
1650 if let Some(p) = self
1652 .user_overridden_properties
1653 .get(node_id)
1654 .and_then(|n| n.get(css_property_type))
1655 {
1656 return Some(p);
1657 }
1658
1659 if let Some(prop_with_conditions) =
1663 node_data.css_props.as_ref().iter().rev().find(|prop| {
1664 prop.property.get_type() == *css_property_type && prop.matches(context)
1665 })
1666 {
1667 return Some(&prop_with_conditions.property);
1668 }
1669
1670 let legacy_state = StyledNodeState::from_pseudo_state_flags(&context.pseudo_state);
1672 if let Some(p) = self.get_property(node_data, node_id, &legacy_state, css_property_type) {
1673 return Some(p);
1674 }
1675
1676 None
1677 }
1678
1679 pub fn check_properties_changed(
1682 node_data: &NodeData,
1683 old_context: &DynamicSelectorContext,
1684 new_context: &DynamicSelectorContext,
1685 ) -> bool {
1686 for prop in node_data.css_props.as_ref().iter() {
1687 let was_active = prop.matches(old_context);
1688 let is_active = prop.matches(new_context);
1689 if was_active != is_active {
1690 return true;
1691 }
1692 }
1693 false
1694 }
1695
1696 pub fn check_layout_properties_changed(
1699 node_data: &NodeData,
1700 old_context: &DynamicSelectorContext,
1701 new_context: &DynamicSelectorContext,
1702 ) -> bool {
1703 for prop in node_data.css_props.as_ref().iter() {
1704 if !prop.is_layout_affecting() {
1706 continue;
1707 }
1708
1709 let was_active = prop.matches(old_context);
1710 let is_active = prop.matches(new_context);
1711 if was_active != is_active {
1712 return true;
1713 }
1714 }
1715 false
1716 }
1717
1718 pub fn get_background_content<'a>(
1719 &'a self,
1720 node_data: &'a NodeData,
1721 node_id: &NodeId,
1722 node_state: &StyledNodeState,
1723 ) -> Option<&'a StyleBackgroundContentVecValue> {
1724 self.get_property(
1725 node_data,
1726 node_id,
1727 node_state,
1728 &CssPropertyType::BackgroundContent,
1729 )
1730 .and_then(|p| p.as_background_content())
1731 }
1732
1733 pub fn get_hyphens<'a>(
1735 &'a self,
1736 node_data: &'a NodeData,
1737 node_id: &NodeId,
1738 node_state: &StyledNodeState,
1739 ) -> Option<&'a StyleHyphensValue> {
1740 self.get_property(node_data, node_id, node_state, &CssPropertyType::Hyphens)
1741 .and_then(|p| p.as_hyphens())
1742 }
1743
1744 pub fn get_direction<'a>(
1746 &'a self,
1747 node_data: &'a NodeData,
1748 node_id: &NodeId,
1749 node_state: &StyledNodeState,
1750 ) -> Option<&'a StyleDirectionValue> {
1751 self.get_property(node_data, node_id, node_state, &CssPropertyType::Direction)
1752 .and_then(|p| p.as_direction())
1753 }
1754
1755 pub fn get_white_space<'a>(
1757 &'a self,
1758 node_data: &'a NodeData,
1759 node_id: &NodeId,
1760 node_state: &StyledNodeState,
1761 ) -> Option<&'a StyleWhiteSpaceValue> {
1762 self.get_property(node_data, node_id, node_state, &CssPropertyType::WhiteSpace)
1763 .and_then(|p| p.as_white_space())
1764 }
1765 pub fn get_background_position<'a>(
1766 &'a self,
1767 node_data: &'a NodeData,
1768 node_id: &NodeId,
1769 node_state: &StyledNodeState,
1770 ) -> Option<&'a StyleBackgroundPositionVecValue> {
1771 self.get_property(
1772 node_data,
1773 node_id,
1774 node_state,
1775 &CssPropertyType::BackgroundPosition,
1776 )
1777 .and_then(|p| p.as_background_position())
1778 }
1779 pub fn get_background_size<'a>(
1780 &'a self,
1781 node_data: &'a NodeData,
1782 node_id: &NodeId,
1783 node_state: &StyledNodeState,
1784 ) -> Option<&'a StyleBackgroundSizeVecValue> {
1785 self.get_property(
1786 node_data,
1787 node_id,
1788 node_state,
1789 &CssPropertyType::BackgroundSize,
1790 )
1791 .and_then(|p| p.as_background_size())
1792 }
1793 pub fn get_background_repeat<'a>(
1794 &'a self,
1795 node_data: &'a NodeData,
1796 node_id: &NodeId,
1797 node_state: &StyledNodeState,
1798 ) -> Option<&'a StyleBackgroundRepeatVecValue> {
1799 self.get_property(
1800 node_data,
1801 node_id,
1802 node_state,
1803 &CssPropertyType::BackgroundRepeat,
1804 )
1805 .and_then(|p| p.as_background_repeat())
1806 }
1807 pub fn get_font_size<'a>(
1808 &'a self,
1809 node_data: &'a NodeData,
1810 node_id: &NodeId,
1811 node_state: &StyledNodeState,
1812 ) -> Option<&'a StyleFontSizeValue> {
1813 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontSize)
1814 .and_then(|p| p.as_font_size())
1815 }
1816 pub fn get_font_family<'a>(
1817 &'a self,
1818 node_data: &'a NodeData,
1819 node_id: &NodeId,
1820 node_state: &StyledNodeState,
1821 ) -> Option<&'a StyleFontFamilyVecValue> {
1822 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontFamily)
1823 .and_then(|p| p.as_font_family())
1824 }
1825 pub fn get_font_weight<'a>(
1826 &'a self,
1827 node_data: &'a NodeData,
1828 node_id: &NodeId,
1829 node_state: &StyledNodeState,
1830 ) -> Option<&'a StyleFontWeightValue> {
1831 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontWeight)
1832 .and_then(|p| p.as_font_weight())
1833 }
1834 pub fn get_font_style<'a>(
1835 &'a self,
1836 node_data: &'a NodeData,
1837 node_id: &NodeId,
1838 node_state: &StyledNodeState,
1839 ) -> Option<&'a StyleFontStyleValue> {
1840 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontStyle)
1841 .and_then(|p| p.as_font_style())
1842 }
1843 pub fn get_text_color<'a>(
1844 &'a self,
1845 node_data: &'a NodeData,
1846 node_id: &NodeId,
1847 node_state: &StyledNodeState,
1848 ) -> Option<&'a StyleTextColorValue> {
1849 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextColor)
1850 .and_then(|p| p.as_text_color())
1851 }
1852 pub fn get_text_indent<'a>(
1854 &'a self,
1855 node_data: &'a NodeData,
1856 node_id: &NodeId,
1857 node_state: &StyledNodeState,
1858 ) -> Option<&'a StyleTextIndentValue> {
1859 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextIndent)
1860 .and_then(|p| p.as_text_indent())
1861 }
1862 pub fn get_initial_letter<'a>(
1864 &'a self,
1865 node_data: &'a NodeData,
1866 node_id: &NodeId,
1867 node_state: &StyledNodeState,
1868 ) -> Option<&'a StyleInitialLetterValue> {
1869 self.get_property(
1870 node_data,
1871 node_id,
1872 node_state,
1873 &CssPropertyType::InitialLetter,
1874 )
1875 .and_then(|p| p.as_initial_letter())
1876 }
1877 pub fn get_line_clamp<'a>(
1879 &'a self,
1880 node_data: &'a NodeData,
1881 node_id: &NodeId,
1882 node_state: &StyledNodeState,
1883 ) -> Option<&'a StyleLineClampValue> {
1884 self.get_property(node_data, node_id, node_state, &CssPropertyType::LineClamp)
1885 .and_then(|p| p.as_line_clamp())
1886 }
1887 pub fn get_hanging_punctuation<'a>(
1889 &'a self,
1890 node_data: &'a NodeData,
1891 node_id: &NodeId,
1892 node_state: &StyledNodeState,
1893 ) -> Option<&'a StyleHangingPunctuationValue> {
1894 self.get_property(
1895 node_data,
1896 node_id,
1897 node_state,
1898 &CssPropertyType::HangingPunctuation,
1899 )
1900 .and_then(|p| p.as_hanging_punctuation())
1901 }
1902 pub fn get_text_combine_upright<'a>(
1904 &'a self,
1905 node_data: &'a NodeData,
1906 node_id: &NodeId,
1907 node_state: &StyledNodeState,
1908 ) -> Option<&'a StyleTextCombineUprightValue> {
1909 self.get_property(
1910 node_data,
1911 node_id,
1912 node_state,
1913 &CssPropertyType::TextCombineUpright,
1914 )
1915 .and_then(|p| p.as_text_combine_upright())
1916 }
1917 pub fn get_exclusion_margin<'a>(
1919 &'a self,
1920 node_data: &'a NodeData,
1921 node_id: &NodeId,
1922 node_state: &StyledNodeState,
1923 ) -> Option<&'a StyleExclusionMarginValue> {
1924 self.get_property(
1925 node_data,
1926 node_id,
1927 node_state,
1928 &CssPropertyType::ExclusionMargin,
1929 )
1930 .and_then(|p| p.as_exclusion_margin())
1931 }
1932 pub fn get_hyphenation_language<'a>(
1934 &'a self,
1935 node_data: &'a NodeData,
1936 node_id: &NodeId,
1937 node_state: &StyledNodeState,
1938 ) -> Option<&'a StyleHyphenationLanguageValue> {
1939 self.get_property(
1940 node_data,
1941 node_id,
1942 node_state,
1943 &CssPropertyType::HyphenationLanguage,
1944 )
1945 .and_then(|p| p.as_hyphenation_language())
1946 }
1947 pub fn get_caret_color<'a>(
1949 &'a self,
1950 node_data: &'a NodeData,
1951 node_id: &NodeId,
1952 node_state: &StyledNodeState,
1953 ) -> Option<&'a CaretColorValue> {
1954 self.get_property(node_data, node_id, node_state, &CssPropertyType::CaretColor)
1955 .and_then(|p| p.as_caret_color())
1956 }
1957
1958 pub fn get_caret_width<'a>(
1960 &'a self,
1961 node_data: &'a NodeData,
1962 node_id: &NodeId,
1963 node_state: &StyledNodeState,
1964 ) -> Option<&'a CaretWidthValue> {
1965 self.get_property(node_data, node_id, node_state, &CssPropertyType::CaretWidth)
1966 .and_then(|p| p.as_caret_width())
1967 }
1968
1969 pub fn get_caret_animation_duration<'a>(
1971 &'a self,
1972 node_data: &'a NodeData,
1973 node_id: &NodeId,
1974 node_state: &StyledNodeState,
1975 ) -> Option<&'a CaretAnimationDurationValue> {
1976 self.get_property(
1977 node_data,
1978 node_id,
1979 node_state,
1980 &CssPropertyType::CaretAnimationDuration,
1981 )
1982 .and_then(|p| p.as_caret_animation_duration())
1983 }
1984
1985 pub fn get_selection_background_color<'a>(
1987 &'a self,
1988 node_data: &'a NodeData,
1989 node_id: &NodeId,
1990 node_state: &StyledNodeState,
1991 ) -> Option<&'a SelectionBackgroundColorValue> {
1992 self.get_property(
1993 node_data,
1994 node_id,
1995 node_state,
1996 &CssPropertyType::SelectionBackgroundColor,
1997 )
1998 .and_then(|p| p.as_selection_background_color())
1999 }
2000
2001 pub fn get_selection_color<'a>(
2003 &'a self,
2004 node_data: &'a NodeData,
2005 node_id: &NodeId,
2006 node_state: &StyledNodeState,
2007 ) -> Option<&'a SelectionColorValue> {
2008 self.get_property(
2009 node_data,
2010 node_id,
2011 node_state,
2012 &CssPropertyType::SelectionColor,
2013 )
2014 .and_then(|p| p.as_selection_color())
2015 }
2016
2017 pub fn get_selection_radius<'a>(
2019 &'a self,
2020 node_data: &'a NodeData,
2021 node_id: &NodeId,
2022 node_state: &StyledNodeState,
2023 ) -> Option<&'a SelectionRadiusValue> {
2024 self.get_property(
2025 node_data,
2026 node_id,
2027 node_state,
2028 &CssPropertyType::SelectionRadius,
2029 )
2030 .and_then(|p| p.as_selection_radius())
2031 }
2032
2033 pub fn get_text_justify<'a>(
2035 &'a self,
2036 node_data: &'a NodeData,
2037 node_id: &NodeId,
2038 node_state: &StyledNodeState,
2039 ) -> Option<&'a LayoutTextJustifyValue> {
2040 self.get_property(
2041 node_data,
2042 node_id,
2043 node_state,
2044 &CssPropertyType::TextJustify,
2045 )
2046 .and_then(|p| p.as_text_justify())
2047 }
2048
2049 pub fn get_z_index<'a>(
2051 &'a self,
2052 node_data: &'a NodeData,
2053 node_id: &NodeId,
2054 node_state: &StyledNodeState,
2055 ) -> Option<&'a LayoutZIndexValue> {
2056 self.get_property(node_data, node_id, node_state, &CssPropertyType::ZIndex)
2057 .and_then(|p| p.as_z_index())
2058 }
2059
2060 pub fn get_flex_basis<'a>(
2062 &'a self,
2063 node_data: &'a NodeData,
2064 node_id: &NodeId,
2065 node_state: &StyledNodeState,
2066 ) -> Option<&'a LayoutFlexBasisValue> {
2067 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexBasis)
2068 .and_then(|p| p.as_flex_basis())
2069 }
2070
2071 pub fn get_column_gap<'a>(
2073 &'a self,
2074 node_data: &'a NodeData,
2075 node_id: &NodeId,
2076 node_state: &StyledNodeState,
2077 ) -> Option<&'a LayoutColumnGapValue> {
2078 self.get_property(node_data, node_id, node_state, &CssPropertyType::ColumnGap)
2079 .and_then(|p| p.as_column_gap())
2080 }
2081
2082 pub fn get_row_gap<'a>(
2084 &'a self,
2085 node_data: &'a NodeData,
2086 node_id: &NodeId,
2087 node_state: &StyledNodeState,
2088 ) -> Option<&'a LayoutRowGapValue> {
2089 self.get_property(node_data, node_id, node_state, &CssPropertyType::RowGap)
2090 .and_then(|p| p.as_row_gap())
2091 }
2092
2093 pub fn get_grid_template_columns<'a>(
2095 &'a self,
2096 node_data: &'a NodeData,
2097 node_id: &NodeId,
2098 node_state: &StyledNodeState,
2099 ) -> Option<&'a LayoutGridTemplateColumnsValue> {
2100 self.get_property(
2101 node_data,
2102 node_id,
2103 node_state,
2104 &CssPropertyType::GridTemplateColumns,
2105 )
2106 .and_then(|p| p.as_grid_template_columns())
2107 }
2108
2109 pub fn get_grid_template_rows<'a>(
2111 &'a self,
2112 node_data: &'a NodeData,
2113 node_id: &NodeId,
2114 node_state: &StyledNodeState,
2115 ) -> Option<&'a LayoutGridTemplateRowsValue> {
2116 self.get_property(
2117 node_data,
2118 node_id,
2119 node_state,
2120 &CssPropertyType::GridTemplateRows,
2121 )
2122 .and_then(|p| p.as_grid_template_rows())
2123 }
2124
2125 pub fn get_grid_auto_columns<'a>(
2127 &'a self,
2128 node_data: &'a NodeData,
2129 node_id: &NodeId,
2130 node_state: &StyledNodeState,
2131 ) -> Option<&'a LayoutGridAutoColumnsValue> {
2132 self.get_property(
2133 node_data,
2134 node_id,
2135 node_state,
2136 &CssPropertyType::GridAutoColumns,
2137 )
2138 .and_then(|p| p.as_grid_auto_columns())
2139 }
2140
2141 pub fn get_grid_auto_rows<'a>(
2143 &'a self,
2144 node_data: &'a NodeData,
2145 node_id: &NodeId,
2146 node_state: &StyledNodeState,
2147 ) -> Option<&'a LayoutGridAutoRowsValue> {
2148 self.get_property(
2149 node_data,
2150 node_id,
2151 node_state,
2152 &CssPropertyType::GridAutoRows,
2153 )
2154 .and_then(|p| p.as_grid_auto_rows())
2155 }
2156
2157 pub fn get_grid_column<'a>(
2159 &'a self,
2160 node_data: &'a NodeData,
2161 node_id: &NodeId,
2162 node_state: &StyledNodeState,
2163 ) -> Option<&'a LayoutGridColumnValue> {
2164 self.get_property(node_data, node_id, node_state, &CssPropertyType::GridColumn)
2165 .and_then(|p| p.as_grid_column())
2166 }
2167
2168 pub fn get_grid_row<'a>(
2170 &'a self,
2171 node_data: &'a NodeData,
2172 node_id: &NodeId,
2173 node_state: &StyledNodeState,
2174 ) -> Option<&'a LayoutGridRowValue> {
2175 self.get_property(node_data, node_id, node_state, &CssPropertyType::GridRow)
2176 .and_then(|p| p.as_grid_row())
2177 }
2178
2179 pub fn get_grid_auto_flow<'a>(
2181 &'a self,
2182 node_data: &'a NodeData,
2183 node_id: &NodeId,
2184 node_state: &StyledNodeState,
2185 ) -> Option<&'a LayoutGridAutoFlowValue> {
2186 self.get_property(
2187 node_data,
2188 node_id,
2189 node_state,
2190 &CssPropertyType::GridAutoFlow,
2191 )
2192 .and_then(|p| p.as_grid_auto_flow())
2193 }
2194
2195 pub fn get_justify_self<'a>(
2197 &'a self,
2198 node_data: &'a NodeData,
2199 node_id: &NodeId,
2200 node_state: &StyledNodeState,
2201 ) -> Option<&'a LayoutJustifySelfValue> {
2202 self.get_property(
2203 node_data,
2204 node_id,
2205 node_state,
2206 &CssPropertyType::JustifySelf,
2207 )
2208 .and_then(|p| p.as_justify_self())
2209 }
2210
2211 pub fn get_justify_items<'a>(
2213 &'a self,
2214 node_data: &'a NodeData,
2215 node_id: &NodeId,
2216 node_state: &StyledNodeState,
2217 ) -> Option<&'a LayoutJustifyItemsValue> {
2218 self.get_property(
2219 node_data,
2220 node_id,
2221 node_state,
2222 &CssPropertyType::JustifyItems,
2223 )
2224 .and_then(|p| p.as_justify_items())
2225 }
2226
2227 pub fn get_gap<'a>(
2229 &'a self,
2230 node_data: &'a NodeData,
2231 node_id: &NodeId,
2232 node_state: &StyledNodeState,
2233 ) -> Option<&'a LayoutGapValue> {
2234 self.get_property(node_data, node_id, node_state, &CssPropertyType::Gap)
2235 .and_then(|p| p.as_gap())
2236 }
2237
2238 pub fn get_grid_gap<'a>(
2240 &'a self,
2241 node_data: &'a NodeData,
2242 node_id: &NodeId,
2243 node_state: &StyledNodeState,
2244 ) -> Option<&'a LayoutGapValue> {
2245 self.get_property(node_data, node_id, node_state, &CssPropertyType::GridGap)
2246 .and_then(|p| p.as_grid_gap())
2247 }
2248
2249 pub fn get_align_self<'a>(
2251 &'a self,
2252 node_data: &'a NodeData,
2253 node_id: &NodeId,
2254 node_state: &StyledNodeState,
2255 ) -> Option<&'a LayoutAlignSelfValue> {
2256 self.get_property(node_data, node_id, node_state, &CssPropertyType::AlignSelf)
2257 .and_then(|p| p.as_align_self())
2258 }
2259
2260 pub fn get_font<'a>(
2262 &'a self,
2263 node_data: &'a NodeData,
2264 node_id: &NodeId,
2265 node_state: &StyledNodeState,
2266 ) -> Option<&'a StyleFontValue> {
2267 self.get_property(node_data, node_id, node_state, &CssPropertyType::Font)
2268 .and_then(|p| p.as_font())
2269 }
2270
2271 pub fn get_writing_mode<'a>(
2273 &'a self,
2274 node_data: &'a NodeData,
2275 node_id: &NodeId,
2276 node_state: &StyledNodeState,
2277 ) -> Option<&'a LayoutWritingModeValue> {
2278 self.get_property(
2279 node_data,
2280 node_id,
2281 node_state,
2282 &CssPropertyType::WritingMode,
2283 )
2284 .and_then(|p| p.as_writing_mode())
2285 }
2286
2287 pub fn get_clear<'a>(
2289 &'a self,
2290 node_data: &'a NodeData,
2291 node_id: &NodeId,
2292 node_state: &StyledNodeState,
2293 ) -> Option<&'a LayoutClearValue> {
2294 self.get_property(node_data, node_id, node_state, &CssPropertyType::Clear)
2295 .and_then(|p| p.as_clear())
2296 }
2297
2298 pub fn get_shape_outside<'a>(
2300 &'a self,
2301 node_data: &'a NodeData,
2302 node_id: &NodeId,
2303 node_state: &StyledNodeState,
2304 ) -> Option<&'a ShapeOutsideValue> {
2305 self.get_property(
2306 node_data,
2307 node_id,
2308 node_state,
2309 &CssPropertyType::ShapeOutside,
2310 )
2311 .and_then(|p| p.as_shape_outside())
2312 }
2313
2314 pub fn get_shape_inside<'a>(
2316 &'a self,
2317 node_data: &'a NodeData,
2318 node_id: &NodeId,
2319 node_state: &StyledNodeState,
2320 ) -> Option<&'a ShapeInsideValue> {
2321 self.get_property(
2322 node_data,
2323 node_id,
2324 node_state,
2325 &CssPropertyType::ShapeInside,
2326 )
2327 .and_then(|p| p.as_shape_inside())
2328 }
2329
2330 pub fn get_clip_path<'a>(
2332 &'a self,
2333 node_data: &'a NodeData,
2334 node_id: &NodeId,
2335 node_state: &StyledNodeState,
2336 ) -> Option<&'a ClipPathValue> {
2337 self.get_property(node_data, node_id, node_state, &CssPropertyType::ClipPath)
2338 .and_then(|p| p.as_clip_path())
2339 }
2340
2341 pub fn get_scrollbar_style<'a>(
2343 &'a self,
2344 node_data: &'a NodeData,
2345 node_id: &NodeId,
2346 node_state: &StyledNodeState,
2347 ) -> Option<&'a ScrollbarStyleValue> {
2348 self.get_property(node_data, node_id, node_state, &CssPropertyType::Scrollbar)
2349 .and_then(|p| p.as_scrollbar())
2350 }
2351
2352 pub fn get_scrollbar_width<'a>(
2354 &'a self,
2355 node_data: &'a NodeData,
2356 node_id: &NodeId,
2357 node_state: &StyledNodeState,
2358 ) -> Option<&'a LayoutScrollbarWidthValue> {
2359 self.get_property(
2360 node_data,
2361 node_id,
2362 node_state,
2363 &CssPropertyType::ScrollbarWidth,
2364 )
2365 .and_then(|p| p.as_scrollbar_width())
2366 }
2367
2368 pub fn get_scrollbar_color<'a>(
2370 &'a self,
2371 node_data: &'a NodeData,
2372 node_id: &NodeId,
2373 node_state: &StyledNodeState,
2374 ) -> Option<&'a StyleScrollbarColorValue> {
2375 self.get_property(
2376 node_data,
2377 node_id,
2378 node_state,
2379 &CssPropertyType::ScrollbarColor,
2380 )
2381 .and_then(|p| p.as_scrollbar_color())
2382 }
2383
2384 pub fn get_visibility<'a>(
2386 &'a self,
2387 node_data: &'a NodeData,
2388 node_id: &NodeId,
2389 node_state: &StyledNodeState,
2390 ) -> Option<&'a StyleVisibilityValue> {
2391 self.get_property(node_data, node_id, node_state, &CssPropertyType::Visibility)
2392 .and_then(|p| p.as_visibility())
2393 }
2394
2395 pub fn get_break_before<'a>(
2397 &'a self,
2398 node_data: &'a NodeData,
2399 node_id: &NodeId,
2400 node_state: &StyledNodeState,
2401 ) -> Option<&'a PageBreakValue> {
2402 self.get_property(
2403 node_data,
2404 node_id,
2405 node_state,
2406 &CssPropertyType::BreakBefore,
2407 )
2408 .and_then(|p| p.as_break_before())
2409 }
2410
2411 pub fn get_break_after<'a>(
2413 &'a self,
2414 node_data: &'a NodeData,
2415 node_id: &NodeId,
2416 node_state: &StyledNodeState,
2417 ) -> Option<&'a PageBreakValue> {
2418 self.get_property(node_data, node_id, node_state, &CssPropertyType::BreakAfter)
2419 .and_then(|p| p.as_break_after())
2420 }
2421
2422 pub fn get_break_inside<'a>(
2424 &'a self,
2425 node_data: &'a NodeData,
2426 node_id: &NodeId,
2427 node_state: &StyledNodeState,
2428 ) -> Option<&'a BreakInsideValue> {
2429 self.get_property(
2430 node_data,
2431 node_id,
2432 node_state,
2433 &CssPropertyType::BreakInside,
2434 )
2435 .and_then(|p| p.as_break_inside())
2436 }
2437
2438 pub fn get_orphans<'a>(
2440 &'a self,
2441 node_data: &'a NodeData,
2442 node_id: &NodeId,
2443 node_state: &StyledNodeState,
2444 ) -> Option<&'a OrphansValue> {
2445 self.get_property(node_data, node_id, node_state, &CssPropertyType::Orphans)
2446 .and_then(|p| p.as_orphans())
2447 }
2448
2449 pub fn get_widows<'a>(
2451 &'a self,
2452 node_data: &'a NodeData,
2453 node_id: &NodeId,
2454 node_state: &StyledNodeState,
2455 ) -> Option<&'a WidowsValue> {
2456 self.get_property(node_data, node_id, node_state, &CssPropertyType::Widows)
2457 .and_then(|p| p.as_widows())
2458 }
2459
2460 pub fn get_box_decoration_break<'a>(
2462 &'a self,
2463 node_data: &'a NodeData,
2464 node_id: &NodeId,
2465 node_state: &StyledNodeState,
2466 ) -> Option<&'a BoxDecorationBreakValue> {
2467 self.get_property(
2468 node_data,
2469 node_id,
2470 node_state,
2471 &CssPropertyType::BoxDecorationBreak,
2472 )
2473 .and_then(|p| p.as_box_decoration_break())
2474 }
2475
2476 pub fn get_column_count<'a>(
2478 &'a self,
2479 node_data: &'a NodeData,
2480 node_id: &NodeId,
2481 node_state: &StyledNodeState,
2482 ) -> Option<&'a ColumnCountValue> {
2483 self.get_property(
2484 node_data,
2485 node_id,
2486 node_state,
2487 &CssPropertyType::ColumnCount,
2488 )
2489 .and_then(|p| p.as_column_count())
2490 }
2491
2492 pub fn get_column_width<'a>(
2494 &'a self,
2495 node_data: &'a NodeData,
2496 node_id: &NodeId,
2497 node_state: &StyledNodeState,
2498 ) -> Option<&'a ColumnWidthValue> {
2499 self.get_property(
2500 node_data,
2501 node_id,
2502 node_state,
2503 &CssPropertyType::ColumnWidth,
2504 )
2505 .and_then(|p| p.as_column_width())
2506 }
2507
2508 pub fn get_column_span<'a>(
2510 &'a self,
2511 node_data: &'a NodeData,
2512 node_id: &NodeId,
2513 node_state: &StyledNodeState,
2514 ) -> Option<&'a ColumnSpanValue> {
2515 self.get_property(node_data, node_id, node_state, &CssPropertyType::ColumnSpan)
2516 .and_then(|p| p.as_column_span())
2517 }
2518
2519 pub fn get_column_fill<'a>(
2521 &'a self,
2522 node_data: &'a NodeData,
2523 node_id: &NodeId,
2524 node_state: &StyledNodeState,
2525 ) -> Option<&'a ColumnFillValue> {
2526 self.get_property(node_data, node_id, node_state, &CssPropertyType::ColumnFill)
2527 .and_then(|p| p.as_column_fill())
2528 }
2529
2530 pub fn get_column_rule_width<'a>(
2532 &'a self,
2533 node_data: &'a NodeData,
2534 node_id: &NodeId,
2535 node_state: &StyledNodeState,
2536 ) -> Option<&'a ColumnRuleWidthValue> {
2537 self.get_property(
2538 node_data,
2539 node_id,
2540 node_state,
2541 &CssPropertyType::ColumnRuleWidth,
2542 )
2543 .and_then(|p| p.as_column_rule_width())
2544 }
2545
2546 pub fn get_column_rule_style<'a>(
2548 &'a self,
2549 node_data: &'a NodeData,
2550 node_id: &NodeId,
2551 node_state: &StyledNodeState,
2552 ) -> Option<&'a ColumnRuleStyleValue> {
2553 self.get_property(
2554 node_data,
2555 node_id,
2556 node_state,
2557 &CssPropertyType::ColumnRuleStyle,
2558 )
2559 .and_then(|p| p.as_column_rule_style())
2560 }
2561
2562 pub fn get_column_rule_color<'a>(
2564 &'a self,
2565 node_data: &'a NodeData,
2566 node_id: &NodeId,
2567 node_state: &StyledNodeState,
2568 ) -> Option<&'a ColumnRuleColorValue> {
2569 self.get_property(
2570 node_data,
2571 node_id,
2572 node_state,
2573 &CssPropertyType::ColumnRuleColor,
2574 )
2575 .and_then(|p| p.as_column_rule_color())
2576 }
2577
2578 pub fn get_flow_into<'a>(
2580 &'a self,
2581 node_data: &'a NodeData,
2582 node_id: &NodeId,
2583 node_state: &StyledNodeState,
2584 ) -> Option<&'a FlowIntoValue> {
2585 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlowInto)
2586 .and_then(|p| p.as_flow_into())
2587 }
2588
2589 pub fn get_flow_from<'a>(
2591 &'a self,
2592 node_data: &'a NodeData,
2593 node_id: &NodeId,
2594 node_state: &StyledNodeState,
2595 ) -> Option<&'a FlowFromValue> {
2596 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlowFrom)
2597 .and_then(|p| p.as_flow_from())
2598 }
2599
2600 pub fn get_shape_margin<'a>(
2602 &'a self,
2603 node_data: &'a NodeData,
2604 node_id: &NodeId,
2605 node_state: &StyledNodeState,
2606 ) -> Option<&'a ShapeMarginValue> {
2607 self.get_property(
2608 node_data,
2609 node_id,
2610 node_state,
2611 &CssPropertyType::ShapeMargin,
2612 )
2613 .and_then(|p| p.as_shape_margin())
2614 }
2615
2616 pub fn get_shape_image_threshold<'a>(
2618 &'a self,
2619 node_data: &'a NodeData,
2620 node_id: &NodeId,
2621 node_state: &StyledNodeState,
2622 ) -> Option<&'a ShapeImageThresholdValue> {
2623 self.get_property(
2624 node_data,
2625 node_id,
2626 node_state,
2627 &CssPropertyType::ShapeImageThreshold,
2628 )
2629 .and_then(|p| p.as_shape_image_threshold())
2630 }
2631
2632 pub fn get_content<'a>(
2634 &'a self,
2635 node_data: &'a NodeData,
2636 node_id: &NodeId,
2637 node_state: &StyledNodeState,
2638 ) -> Option<&'a ContentValue> {
2639 self.get_property(node_data, node_id, node_state, &CssPropertyType::Content)
2640 .and_then(|p| p.as_content())
2641 }
2642
2643 pub fn get_counter_reset<'a>(
2645 &'a self,
2646 node_data: &'a NodeData,
2647 node_id: &NodeId,
2648 node_state: &StyledNodeState,
2649 ) -> Option<&'a CounterResetValue> {
2650 self.get_property(
2651 node_data,
2652 node_id,
2653 node_state,
2654 &CssPropertyType::CounterReset,
2655 )
2656 .and_then(|p| p.as_counter_reset())
2657 }
2658
2659 pub fn get_counter_increment<'a>(
2661 &'a self,
2662 node_data: &'a NodeData,
2663 node_id: &NodeId,
2664 node_state: &StyledNodeState,
2665 ) -> Option<&'a CounterIncrementValue> {
2666 self.get_property(
2667 node_data,
2668 node_id,
2669 node_state,
2670 &CssPropertyType::CounterIncrement,
2671 )
2672 .and_then(|p| p.as_counter_increment())
2673 }
2674
2675 pub fn get_string_set<'a>(
2677 &'a self,
2678 node_data: &'a NodeData,
2679 node_id: &NodeId,
2680 node_state: &StyledNodeState,
2681 ) -> Option<&'a StringSetValue> {
2682 self.get_property(node_data, node_id, node_state, &CssPropertyType::StringSet)
2683 .and_then(|p| p.as_string_set())
2684 }
2685 pub fn get_text_align<'a>(
2686 &'a self,
2687 node_data: &'a NodeData,
2688 node_id: &NodeId,
2689 node_state: &StyledNodeState,
2690 ) -> Option<&'a StyleTextAlignValue> {
2691 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextAlign)
2692 .and_then(|p| p.as_text_align())
2693 }
2694 pub fn get_user_select<'a>(
2695 &'a self,
2696 node_data: &'a NodeData,
2697 node_id: &NodeId,
2698 node_state: &StyledNodeState,
2699 ) -> Option<&'a StyleUserSelectValue> {
2700 self.get_property(node_data, node_id, node_state, &CssPropertyType::UserSelect)
2701 .and_then(|p| p.as_user_select())
2702 }
2703 pub fn get_text_decoration<'a>(
2704 &'a self,
2705 node_data: &'a NodeData,
2706 node_id: &NodeId,
2707 node_state: &StyledNodeState,
2708 ) -> Option<&'a StyleTextDecorationValue> {
2709 self.get_property(
2710 node_data,
2711 node_id,
2712 node_state,
2713 &CssPropertyType::TextDecoration,
2714 )
2715 .and_then(|p| p.as_text_decoration())
2716 }
2717 pub fn get_vertical_align<'a>(
2718 &'a self,
2719 node_data: &'a NodeData,
2720 node_id: &NodeId,
2721 node_state: &StyledNodeState,
2722 ) -> Option<&'a StyleVerticalAlignValue> {
2723 self.get_property(
2724 node_data,
2725 node_id,
2726 node_state,
2727 &CssPropertyType::VerticalAlign,
2728 )
2729 .and_then(|p| p.as_vertical_align())
2730 }
2731 pub fn get_line_height<'a>(
2732 &'a self,
2733 node_data: &'a NodeData,
2734 node_id: &NodeId,
2735 node_state: &StyledNodeState,
2736 ) -> Option<&'a StyleLineHeightValue> {
2737 self.get_property(node_data, node_id, node_state, &CssPropertyType::LineHeight)
2738 .and_then(|p| p.as_line_height())
2739 }
2740 pub fn get_letter_spacing<'a>(
2741 &'a self,
2742 node_data: &'a NodeData,
2743 node_id: &NodeId,
2744 node_state: &StyledNodeState,
2745 ) -> Option<&'a StyleLetterSpacingValue> {
2746 self.get_property(
2747 node_data,
2748 node_id,
2749 node_state,
2750 &CssPropertyType::LetterSpacing,
2751 )
2752 .and_then(|p| p.as_letter_spacing())
2753 }
2754 pub fn get_word_spacing<'a>(
2755 &'a self,
2756 node_data: &'a NodeData,
2757 node_id: &NodeId,
2758 node_state: &StyledNodeState,
2759 ) -> Option<&'a StyleWordSpacingValue> {
2760 self.get_property(
2761 node_data,
2762 node_id,
2763 node_state,
2764 &CssPropertyType::WordSpacing,
2765 )
2766 .and_then(|p| p.as_word_spacing())
2767 }
2768 pub fn get_tab_width<'a>(
2769 &'a self,
2770 node_data: &'a NodeData,
2771 node_id: &NodeId,
2772 node_state: &StyledNodeState,
2773 ) -> Option<&'a StyleTabWidthValue> {
2774 self.get_property(node_data, node_id, node_state, &CssPropertyType::TabWidth)
2775 .and_then(|p| p.as_tab_width())
2776 }
2777 pub fn get_cursor<'a>(
2778 &'a self,
2779 node_data: &'a NodeData,
2780 node_id: &NodeId,
2781 node_state: &StyledNodeState,
2782 ) -> Option<&'a StyleCursorValue> {
2783 self.get_property(node_data, node_id, node_state, &CssPropertyType::Cursor)
2784 .and_then(|p| p.as_cursor())
2785 }
2786 pub fn get_box_shadow_left<'a>(
2787 &'a self,
2788 node_data: &'a NodeData,
2789 node_id: &NodeId,
2790 node_state: &StyledNodeState,
2791 ) -> Option<&'a StyleBoxShadowValue> {
2792 self.get_property(
2793 node_data,
2794 node_id,
2795 node_state,
2796 &CssPropertyType::BoxShadowLeft,
2797 )
2798 .and_then(|p| p.as_box_shadow_left())
2799 }
2800 pub fn get_box_shadow_right<'a>(
2801 &'a self,
2802 node_data: &'a NodeData,
2803 node_id: &NodeId,
2804 node_state: &StyledNodeState,
2805 ) -> Option<&'a StyleBoxShadowValue> {
2806 self.get_property(
2807 node_data,
2808 node_id,
2809 node_state,
2810 &CssPropertyType::BoxShadowRight,
2811 )
2812 .and_then(|p| p.as_box_shadow_right())
2813 }
2814 pub fn get_box_shadow_top<'a>(
2815 &'a self,
2816 node_data: &'a NodeData,
2817 node_id: &NodeId,
2818 node_state: &StyledNodeState,
2819 ) -> Option<&'a StyleBoxShadowValue> {
2820 self.get_property(
2821 node_data,
2822 node_id,
2823 node_state,
2824 &CssPropertyType::BoxShadowTop,
2825 )
2826 .and_then(|p| p.as_box_shadow_top())
2827 }
2828 pub fn get_box_shadow_bottom<'a>(
2829 &'a self,
2830 node_data: &'a NodeData,
2831 node_id: &NodeId,
2832 node_state: &StyledNodeState,
2833 ) -> Option<&'a StyleBoxShadowValue> {
2834 self.get_property(
2835 node_data,
2836 node_id,
2837 node_state,
2838 &CssPropertyType::BoxShadowBottom,
2839 )
2840 .and_then(|p| p.as_box_shadow_bottom())
2841 }
2842 pub fn get_border_top_color<'a>(
2843 &'a self,
2844 node_data: &'a NodeData,
2845 node_id: &NodeId,
2846 node_state: &StyledNodeState,
2847 ) -> Option<&'a StyleBorderTopColorValue> {
2848 self.get_property(
2849 node_data,
2850 node_id,
2851 node_state,
2852 &CssPropertyType::BorderTopColor,
2853 )
2854 .and_then(|p| p.as_border_top_color())
2855 }
2856 pub fn get_border_left_color<'a>(
2857 &'a self,
2858 node_data: &'a NodeData,
2859 node_id: &NodeId,
2860 node_state: &StyledNodeState,
2861 ) -> Option<&'a StyleBorderLeftColorValue> {
2862 self.get_property(
2863 node_data,
2864 node_id,
2865 node_state,
2866 &CssPropertyType::BorderLeftColor,
2867 )
2868 .and_then(|p| p.as_border_left_color())
2869 }
2870 pub fn get_border_right_color<'a>(
2871 &'a self,
2872 node_data: &'a NodeData,
2873 node_id: &NodeId,
2874 node_state: &StyledNodeState,
2875 ) -> Option<&'a StyleBorderRightColorValue> {
2876 self.get_property(
2877 node_data,
2878 node_id,
2879 node_state,
2880 &CssPropertyType::BorderRightColor,
2881 )
2882 .and_then(|p| p.as_border_right_color())
2883 }
2884 pub fn get_border_bottom_color<'a>(
2885 &'a self,
2886 node_data: &'a NodeData,
2887 node_id: &NodeId,
2888 node_state: &StyledNodeState,
2889 ) -> Option<&'a StyleBorderBottomColorValue> {
2890 self.get_property(
2891 node_data,
2892 node_id,
2893 node_state,
2894 &CssPropertyType::BorderBottomColor,
2895 )
2896 .and_then(|p| p.as_border_bottom_color())
2897 }
2898 pub fn get_border_top_style<'a>(
2899 &'a self,
2900 node_data: &'a NodeData,
2901 node_id: &NodeId,
2902 node_state: &StyledNodeState,
2903 ) -> Option<&'a StyleBorderTopStyleValue> {
2904 self.get_property(
2905 node_data,
2906 node_id,
2907 node_state,
2908 &CssPropertyType::BorderTopStyle,
2909 )
2910 .and_then(|p| p.as_border_top_style())
2911 }
2912 pub fn get_border_left_style<'a>(
2913 &'a self,
2914 node_data: &'a NodeData,
2915 node_id: &NodeId,
2916 node_state: &StyledNodeState,
2917 ) -> Option<&'a StyleBorderLeftStyleValue> {
2918 self.get_property(
2919 node_data,
2920 node_id,
2921 node_state,
2922 &CssPropertyType::BorderLeftStyle,
2923 )
2924 .and_then(|p| p.as_border_left_style())
2925 }
2926 pub fn get_border_right_style<'a>(
2927 &'a self,
2928 node_data: &'a NodeData,
2929 node_id: &NodeId,
2930 node_state: &StyledNodeState,
2931 ) -> Option<&'a StyleBorderRightStyleValue> {
2932 self.get_property(
2933 node_data,
2934 node_id,
2935 node_state,
2936 &CssPropertyType::BorderRightStyle,
2937 )
2938 .and_then(|p| p.as_border_right_style())
2939 }
2940 pub fn get_border_bottom_style<'a>(
2941 &'a self,
2942 node_data: &'a NodeData,
2943 node_id: &NodeId,
2944 node_state: &StyledNodeState,
2945 ) -> Option<&'a StyleBorderBottomStyleValue> {
2946 self.get_property(
2947 node_data,
2948 node_id,
2949 node_state,
2950 &CssPropertyType::BorderBottomStyle,
2951 )
2952 .and_then(|p| p.as_border_bottom_style())
2953 }
2954 pub fn get_border_top_left_radius<'a>(
2955 &'a self,
2956 node_data: &'a NodeData,
2957 node_id: &NodeId,
2958 node_state: &StyledNodeState,
2959 ) -> Option<&'a StyleBorderTopLeftRadiusValue> {
2960 self.get_property(
2961 node_data,
2962 node_id,
2963 node_state,
2964 &CssPropertyType::BorderTopLeftRadius,
2965 )
2966 .and_then(|p| p.as_border_top_left_radius())
2967 }
2968 pub fn get_border_top_right_radius<'a>(
2969 &'a self,
2970 node_data: &'a NodeData,
2971 node_id: &NodeId,
2972 node_state: &StyledNodeState,
2973 ) -> Option<&'a StyleBorderTopRightRadiusValue> {
2974 self.get_property(
2975 node_data,
2976 node_id,
2977 node_state,
2978 &CssPropertyType::BorderTopRightRadius,
2979 )
2980 .and_then(|p| p.as_border_top_right_radius())
2981 }
2982 pub fn get_border_bottom_left_radius<'a>(
2983 &'a self,
2984 node_data: &'a NodeData,
2985 node_id: &NodeId,
2986 node_state: &StyledNodeState,
2987 ) -> Option<&'a StyleBorderBottomLeftRadiusValue> {
2988 self.get_property(
2989 node_data,
2990 node_id,
2991 node_state,
2992 &CssPropertyType::BorderBottomLeftRadius,
2993 )
2994 .and_then(|p| p.as_border_bottom_left_radius())
2995 }
2996 pub fn get_border_bottom_right_radius<'a>(
2997 &'a self,
2998 node_data: &'a NodeData,
2999 node_id: &NodeId,
3000 node_state: &StyledNodeState,
3001 ) -> Option<&'a StyleBorderBottomRightRadiusValue> {
3002 self.get_property(
3003 node_data,
3004 node_id,
3005 node_state,
3006 &CssPropertyType::BorderBottomRightRadius,
3007 )
3008 .and_then(|p| p.as_border_bottom_right_radius())
3009 }
3010 pub fn get_opacity<'a>(
3011 &'a self,
3012 node_data: &'a NodeData,
3013 node_id: &NodeId,
3014 node_state: &StyledNodeState,
3015 ) -> Option<&'a StyleOpacityValue> {
3016 self.get_property(node_data, node_id, node_state, &CssPropertyType::Opacity)
3017 .and_then(|p| p.as_opacity())
3018 }
3019 pub fn get_transform<'a>(
3020 &'a self,
3021 node_data: &'a NodeData,
3022 node_id: &NodeId,
3023 node_state: &StyledNodeState,
3024 ) -> Option<&'a StyleTransformVecValue> {
3025 self.get_property(node_data, node_id, node_state, &CssPropertyType::Transform)
3026 .and_then(|p| p.as_transform())
3027 }
3028 pub fn get_transform_origin<'a>(
3029 &'a self,
3030 node_data: &'a NodeData,
3031 node_id: &NodeId,
3032 node_state: &StyledNodeState,
3033 ) -> Option<&'a StyleTransformOriginValue> {
3034 self.get_property(
3035 node_data,
3036 node_id,
3037 node_state,
3038 &CssPropertyType::TransformOrigin,
3039 )
3040 .and_then(|p| p.as_transform_origin())
3041 }
3042 pub fn get_perspective_origin<'a>(
3043 &'a self,
3044 node_data: &'a NodeData,
3045 node_id: &NodeId,
3046 node_state: &StyledNodeState,
3047 ) -> Option<&'a StylePerspectiveOriginValue> {
3048 self.get_property(
3049 node_data,
3050 node_id,
3051 node_state,
3052 &CssPropertyType::PerspectiveOrigin,
3053 )
3054 .and_then(|p| p.as_perspective_origin())
3055 }
3056 pub fn get_backface_visibility<'a>(
3057 &'a self,
3058 node_data: &'a NodeData,
3059 node_id: &NodeId,
3060 node_state: &StyledNodeState,
3061 ) -> Option<&'a StyleBackfaceVisibilityValue> {
3062 self.get_property(
3063 node_data,
3064 node_id,
3065 node_state,
3066 &CssPropertyType::BackfaceVisibility,
3067 )
3068 .and_then(|p| p.as_backface_visibility())
3069 }
3070 pub fn get_display<'a>(
3071 &'a self,
3072 node_data: &'a NodeData,
3073 node_id: &NodeId,
3074 node_state: &StyledNodeState,
3075 ) -> Option<&'a LayoutDisplayValue> {
3076 self.get_property(node_data, node_id, node_state, &CssPropertyType::Display)
3077 .and_then(|p| p.as_display())
3078 }
3079 pub fn get_float<'a>(
3080 &'a self,
3081 node_data: &'a NodeData,
3082 node_id: &NodeId,
3083 node_state: &StyledNodeState,
3084 ) -> Option<&'a LayoutFloatValue> {
3085 self.get_property(node_data, node_id, node_state, &CssPropertyType::Float)
3086 .and_then(|p| p.as_float())
3087 }
3088 pub fn get_box_sizing<'a>(
3089 &'a self,
3090 node_data: &'a NodeData,
3091 node_id: &NodeId,
3092 node_state: &StyledNodeState,
3093 ) -> Option<&'a LayoutBoxSizingValue> {
3094 self.get_property(node_data, node_id, node_state, &CssPropertyType::BoxSizing)
3095 .and_then(|p| p.as_box_sizing())
3096 }
3097 pub fn get_width<'a>(
3098 &'a self,
3099 node_data: &'a NodeData,
3100 node_id: &NodeId,
3101 node_state: &StyledNodeState,
3102 ) -> Option<&'a LayoutWidthValue> {
3103 self.get_property(node_data, node_id, node_state, &CssPropertyType::Width)
3104 .and_then(|p| p.as_width())
3105 }
3106 pub fn get_height<'a>(
3107 &'a self,
3108 node_data: &'a NodeData,
3109 node_id: &NodeId,
3110 node_state: &StyledNodeState,
3111 ) -> Option<&'a LayoutHeightValue> {
3112 self.get_property(node_data, node_id, node_state, &CssPropertyType::Height)
3113 .and_then(|p| p.as_height())
3114 }
3115 pub fn get_min_width<'a>(
3116 &'a self,
3117 node_data: &'a NodeData,
3118 node_id: &NodeId,
3119 node_state: &StyledNodeState,
3120 ) -> Option<&'a LayoutMinWidthValue> {
3121 self.get_property(node_data, node_id, node_state, &CssPropertyType::MinWidth)
3122 .and_then(|p| p.as_min_width())
3123 }
3124 pub fn get_min_height<'a>(
3125 &'a self,
3126 node_data: &'a NodeData,
3127 node_id: &NodeId,
3128 node_state: &StyledNodeState,
3129 ) -> Option<&'a LayoutMinHeightValue> {
3130 self.get_property(node_data, node_id, node_state, &CssPropertyType::MinHeight)
3131 .and_then(|p| p.as_min_height())
3132 }
3133 pub fn get_max_width<'a>(
3134 &'a self,
3135 node_data: &'a NodeData,
3136 node_id: &NodeId,
3137 node_state: &StyledNodeState,
3138 ) -> Option<&'a LayoutMaxWidthValue> {
3139 self.get_property(node_data, node_id, node_state, &CssPropertyType::MaxWidth)
3140 .and_then(|p| p.as_max_width())
3141 }
3142 pub fn get_max_height<'a>(
3143 &'a self,
3144 node_data: &'a NodeData,
3145 node_id: &NodeId,
3146 node_state: &StyledNodeState,
3147 ) -> Option<&'a LayoutMaxHeightValue> {
3148 self.get_property(node_data, node_id, node_state, &CssPropertyType::MaxHeight)
3149 .and_then(|p| p.as_max_height())
3150 }
3151 pub fn get_position<'a>(
3152 &'a self,
3153 node_data: &'a NodeData,
3154 node_id: &NodeId,
3155 node_state: &StyledNodeState,
3156 ) -> Option<&'a LayoutPositionValue> {
3157 self.get_property(node_data, node_id, node_state, &CssPropertyType::Position)
3158 .and_then(|p| p.as_position())
3159 }
3160 pub fn get_top<'a>(
3161 &'a self,
3162 node_data: &'a NodeData,
3163 node_id: &NodeId,
3164 node_state: &StyledNodeState,
3165 ) -> Option<&'a LayoutTopValue> {
3166 self.get_property(node_data, node_id, node_state, &CssPropertyType::Top)
3167 .and_then(|p| p.as_top())
3168 }
3169 pub fn get_bottom<'a>(
3170 &'a self,
3171 node_data: &'a NodeData,
3172 node_id: &NodeId,
3173 node_state: &StyledNodeState,
3174 ) -> Option<&'a LayoutInsetBottomValue> {
3175 self.get_property(node_data, node_id, node_state, &CssPropertyType::Bottom)
3176 .and_then(|p| p.as_bottom())
3177 }
3178 pub fn get_right<'a>(
3179 &'a self,
3180 node_data: &'a NodeData,
3181 node_id: &NodeId,
3182 node_state: &StyledNodeState,
3183 ) -> Option<&'a LayoutRightValue> {
3184 self.get_property(node_data, node_id, node_state, &CssPropertyType::Right)
3185 .and_then(|p| p.as_right())
3186 }
3187 pub fn get_left<'a>(
3188 &'a self,
3189 node_data: &'a NodeData,
3190 node_id: &NodeId,
3191 node_state: &StyledNodeState,
3192 ) -> Option<&'a LayoutLeftValue> {
3193 self.get_property(node_data, node_id, node_state, &CssPropertyType::Left)
3194 .and_then(|p| p.as_left())
3195 }
3196 pub fn get_padding_top<'a>(
3197 &'a self,
3198 node_data: &'a NodeData,
3199 node_id: &NodeId,
3200 node_state: &StyledNodeState,
3201 ) -> Option<&'a LayoutPaddingTopValue> {
3202 self.get_property(node_data, node_id, node_state, &CssPropertyType::PaddingTop)
3203 .and_then(|p| p.as_padding_top())
3204 }
3205 pub fn get_padding_bottom<'a>(
3206 &'a self,
3207 node_data: &'a NodeData,
3208 node_id: &NodeId,
3209 node_state: &StyledNodeState,
3210 ) -> Option<&'a LayoutPaddingBottomValue> {
3211 self.get_property(
3212 node_data,
3213 node_id,
3214 node_state,
3215 &CssPropertyType::PaddingBottom,
3216 )
3217 .and_then(|p| p.as_padding_bottom())
3218 }
3219 pub fn get_padding_left<'a>(
3220 &'a self,
3221 node_data: &'a NodeData,
3222 node_id: &NodeId,
3223 node_state: &StyledNodeState,
3224 ) -> Option<&'a LayoutPaddingLeftValue> {
3225 self.get_property(
3226 node_data,
3227 node_id,
3228 node_state,
3229 &CssPropertyType::PaddingLeft,
3230 )
3231 .and_then(|p| p.as_padding_left())
3232 }
3233 pub fn get_padding_right<'a>(
3234 &'a self,
3235 node_data: &'a NodeData,
3236 node_id: &NodeId,
3237 node_state: &StyledNodeState,
3238 ) -> Option<&'a LayoutPaddingRightValue> {
3239 self.get_property(
3240 node_data,
3241 node_id,
3242 node_state,
3243 &CssPropertyType::PaddingRight,
3244 )
3245 .and_then(|p| p.as_padding_right())
3246 }
3247 pub fn get_margin_top<'a>(
3248 &'a self,
3249 node_data: &'a NodeData,
3250 node_id: &NodeId,
3251 node_state: &StyledNodeState,
3252 ) -> Option<&'a LayoutMarginTopValue> {
3253 self.get_property(node_data, node_id, node_state, &CssPropertyType::MarginTop)
3254 .and_then(|p| p.as_margin_top())
3255 }
3256 pub fn get_margin_bottom<'a>(
3257 &'a self,
3258 node_data: &'a NodeData,
3259 node_id: &NodeId,
3260 node_state: &StyledNodeState,
3261 ) -> Option<&'a LayoutMarginBottomValue> {
3262 self.get_property(
3263 node_data,
3264 node_id,
3265 node_state,
3266 &CssPropertyType::MarginBottom,
3267 )
3268 .and_then(|p| p.as_margin_bottom())
3269 }
3270 pub fn get_margin_left<'a>(
3271 &'a self,
3272 node_data: &'a NodeData,
3273 node_id: &NodeId,
3274 node_state: &StyledNodeState,
3275 ) -> Option<&'a LayoutMarginLeftValue> {
3276 self.get_property(node_data, node_id, node_state, &CssPropertyType::MarginLeft)
3277 .and_then(|p| p.as_margin_left())
3278 }
3279 pub fn get_margin_right<'a>(
3280 &'a self,
3281 node_data: &'a NodeData,
3282 node_id: &NodeId,
3283 node_state: &StyledNodeState,
3284 ) -> Option<&'a LayoutMarginRightValue> {
3285 self.get_property(
3286 node_data,
3287 node_id,
3288 node_state,
3289 &CssPropertyType::MarginRight,
3290 )
3291 .and_then(|p| p.as_margin_right())
3292 }
3293 pub fn get_border_top_width<'a>(
3294 &'a self,
3295 node_data: &'a NodeData,
3296 node_id: &NodeId,
3297 node_state: &StyledNodeState,
3298 ) -> Option<&'a LayoutBorderTopWidthValue> {
3299 self.get_property(
3300 node_data,
3301 node_id,
3302 node_state,
3303 &CssPropertyType::BorderTopWidth,
3304 )
3305 .and_then(|p| p.as_border_top_width())
3306 }
3307 pub fn get_border_left_width<'a>(
3308 &'a self,
3309 node_data: &'a NodeData,
3310 node_id: &NodeId,
3311 node_state: &StyledNodeState,
3312 ) -> Option<&'a LayoutBorderLeftWidthValue> {
3313 self.get_property(
3314 node_data,
3315 node_id,
3316 node_state,
3317 &CssPropertyType::BorderLeftWidth,
3318 )
3319 .and_then(|p| p.as_border_left_width())
3320 }
3321 pub fn get_border_right_width<'a>(
3322 &'a self,
3323 node_data: &'a NodeData,
3324 node_id: &NodeId,
3325 node_state: &StyledNodeState,
3326 ) -> Option<&'a LayoutBorderRightWidthValue> {
3327 self.get_property(
3328 node_data,
3329 node_id,
3330 node_state,
3331 &CssPropertyType::BorderRightWidth,
3332 )
3333 .and_then(|p| p.as_border_right_width())
3334 }
3335 pub fn get_border_bottom_width<'a>(
3336 &'a self,
3337 node_data: &'a NodeData,
3338 node_id: &NodeId,
3339 node_state: &StyledNodeState,
3340 ) -> Option<&'a LayoutBorderBottomWidthValue> {
3341 self.get_property(
3342 node_data,
3343 node_id,
3344 node_state,
3345 &CssPropertyType::BorderBottomWidth,
3346 )
3347 .and_then(|p| p.as_border_bottom_width())
3348 }
3349 pub fn get_overflow_x<'a>(
3350 &'a self,
3351 node_data: &'a NodeData,
3352 node_id: &NodeId,
3353 node_state: &StyledNodeState,
3354 ) -> Option<&'a LayoutOverflowValue> {
3355 self.get_property(node_data, node_id, node_state, &CssPropertyType::OverflowX)
3356 .and_then(|p| p.as_overflow_x())
3357 }
3358 pub fn get_overflow_y<'a>(
3359 &'a self,
3360 node_data: &'a NodeData,
3361 node_id: &NodeId,
3362 node_state: &StyledNodeState,
3363 ) -> Option<&'a LayoutOverflowValue> {
3364 self.get_property(node_data, node_id, node_state, &CssPropertyType::OverflowY)
3365 .and_then(|p| p.as_overflow_y())
3366 }
3367 pub fn get_flex_direction<'a>(
3368 &'a self,
3369 node_data: &'a NodeData,
3370 node_id: &NodeId,
3371 node_state: &StyledNodeState,
3372 ) -> Option<&'a LayoutFlexDirectionValue> {
3373 self.get_property(
3374 node_data,
3375 node_id,
3376 node_state,
3377 &CssPropertyType::FlexDirection,
3378 )
3379 .and_then(|p| p.as_flex_direction())
3380 }
3381 pub fn get_flex_wrap<'a>(
3382 &'a self,
3383 node_data: &'a NodeData,
3384 node_id: &NodeId,
3385 node_state: &StyledNodeState,
3386 ) -> Option<&'a LayoutFlexWrapValue> {
3387 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexWrap)
3388 .and_then(|p| p.as_flex_wrap())
3389 }
3390 pub fn get_flex_grow<'a>(
3391 &'a self,
3392 node_data: &'a NodeData,
3393 node_id: &NodeId,
3394 node_state: &StyledNodeState,
3395 ) -> Option<&'a LayoutFlexGrowValue> {
3396 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexGrow)
3397 .and_then(|p| p.as_flex_grow())
3398 }
3399 pub fn get_flex_shrink<'a>(
3400 &'a self,
3401 node_data: &'a NodeData,
3402 node_id: &NodeId,
3403 node_state: &StyledNodeState,
3404 ) -> Option<&'a LayoutFlexShrinkValue> {
3405 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexShrink)
3406 .and_then(|p| p.as_flex_shrink())
3407 }
3408 pub fn get_justify_content<'a>(
3409 &'a self,
3410 node_data: &'a NodeData,
3411 node_id: &NodeId,
3412 node_state: &StyledNodeState,
3413 ) -> Option<&'a LayoutJustifyContentValue> {
3414 self.get_property(
3415 node_data,
3416 node_id,
3417 node_state,
3418 &CssPropertyType::JustifyContent,
3419 )
3420 .and_then(|p| p.as_justify_content())
3421 }
3422 pub fn get_align_items<'a>(
3423 &'a self,
3424 node_data: &'a NodeData,
3425 node_id: &NodeId,
3426 node_state: &StyledNodeState,
3427 ) -> Option<&'a LayoutAlignItemsValue> {
3428 self.get_property(node_data, node_id, node_state, &CssPropertyType::AlignItems)
3429 .and_then(|p| p.as_align_items())
3430 }
3431 pub fn get_align_content<'a>(
3432 &'a self,
3433 node_data: &'a NodeData,
3434 node_id: &NodeId,
3435 node_state: &StyledNodeState,
3436 ) -> Option<&'a LayoutAlignContentValue> {
3437 self.get_property(
3438 node_data,
3439 node_id,
3440 node_state,
3441 &CssPropertyType::AlignContent,
3442 )
3443 .and_then(|p| p.as_align_content())
3444 }
3445 pub fn get_mix_blend_mode<'a>(
3446 &'a self,
3447 node_data: &'a NodeData,
3448 node_id: &NodeId,
3449 node_state: &StyledNodeState,
3450 ) -> Option<&'a StyleMixBlendModeValue> {
3451 self.get_property(
3452 node_data,
3453 node_id,
3454 node_state,
3455 &CssPropertyType::MixBlendMode,
3456 )
3457 .and_then(|p| p.as_mix_blend_mode())
3458 }
3459 pub fn get_filter<'a>(
3460 &'a self,
3461 node_data: &'a NodeData,
3462 node_id: &NodeId,
3463 node_state: &StyledNodeState,
3464 ) -> Option<&'a StyleFilterVecValue> {
3465 self.get_property(node_data, node_id, node_state, &CssPropertyType::Filter)
3466 .and_then(|p| p.as_filter())
3467 }
3468 pub fn get_backdrop_filter<'a>(
3469 &'a self,
3470 node_data: &'a NodeData,
3471 node_id: &NodeId,
3472 node_state: &StyledNodeState,
3473 ) -> Option<&'a StyleFilterVecValue> {
3474 self.get_property(node_data, node_id, node_state, &CssPropertyType::Filter)
3475 .and_then(|p| p.as_backdrop_filter())
3476 }
3477 pub fn get_text_shadow<'a>(
3478 &'a self,
3479 node_data: &'a NodeData,
3480 node_id: &NodeId,
3481 node_state: &StyledNodeState,
3482 ) -> Option<&'a StyleBoxShadowValue> {
3483 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextShadow)
3484 .and_then(|p| p.as_text_shadow())
3485 }
3486 pub fn get_list_style_type<'a>(
3487 &'a self,
3488 node_data: &'a NodeData,
3489 node_id: &NodeId,
3490 node_state: &StyledNodeState,
3491 ) -> Option<&'a StyleListStyleTypeValue> {
3492 self.get_property(
3493 node_data,
3494 node_id,
3495 node_state,
3496 &CssPropertyType::ListStyleType,
3497 )
3498 .and_then(|p| p.as_list_style_type())
3499 }
3500 pub fn get_list_style_position<'a>(
3501 &'a self,
3502 node_data: &'a NodeData,
3503 node_id: &NodeId,
3504 node_state: &StyledNodeState,
3505 ) -> Option<&'a StyleListStylePositionValue> {
3506 self.get_property(
3507 node_data,
3508 node_id,
3509 node_state,
3510 &CssPropertyType::ListStylePosition,
3511 )
3512 .and_then(|p| p.as_list_style_position())
3513 }
3514 pub fn get_table_layout<'a>(
3515 &'a self,
3516 node_data: &'a NodeData,
3517 node_id: &NodeId,
3518 node_state: &StyledNodeState,
3519 ) -> Option<&'a LayoutTableLayoutValue> {
3520 self.get_property(
3521 node_data,
3522 node_id,
3523 node_state,
3524 &CssPropertyType::TableLayout,
3525 )
3526 .and_then(|p| p.as_table_layout())
3527 }
3528 pub fn get_border_collapse<'a>(
3529 &'a self,
3530 node_data: &'a NodeData,
3531 node_id: &NodeId,
3532 node_state: &StyledNodeState,
3533 ) -> Option<&'a StyleBorderCollapseValue> {
3534 self.get_property(
3535 node_data,
3536 node_id,
3537 node_state,
3538 &CssPropertyType::BorderCollapse,
3539 )
3540 .and_then(|p| p.as_border_collapse())
3541 }
3542 pub fn get_border_spacing<'a>(
3543 &'a self,
3544 node_data: &'a NodeData,
3545 node_id: &NodeId,
3546 node_state: &StyledNodeState,
3547 ) -> Option<&'a LayoutBorderSpacingValue> {
3548 self.get_property(
3549 node_data,
3550 node_id,
3551 node_state,
3552 &CssPropertyType::BorderSpacing,
3553 )
3554 .and_then(|p| p.as_border_spacing())
3555 }
3556 pub fn get_caption_side<'a>(
3557 &'a self,
3558 node_data: &'a NodeData,
3559 node_id: &NodeId,
3560 node_state: &StyledNodeState,
3561 ) -> Option<&'a StyleCaptionSideValue> {
3562 self.get_property(
3563 node_data,
3564 node_id,
3565 node_state,
3566 &CssPropertyType::CaptionSide,
3567 )
3568 .and_then(|p| p.as_caption_side())
3569 }
3570 pub fn get_empty_cells<'a>(
3571 &'a self,
3572 node_data: &'a NodeData,
3573 node_id: &NodeId,
3574 node_state: &StyledNodeState,
3575 ) -> Option<&'a StyleEmptyCellsValue> {
3576 self.get_property(node_data, node_id, node_state, &CssPropertyType::EmptyCells)
3577 .and_then(|p| p.as_empty_cells())
3578 }
3579
3580 pub fn calc_width(
3582 &self,
3583 node_data: &NodeData,
3584 node_id: &NodeId,
3585 styled_node_state: &StyledNodeState,
3586 reference_width: f32,
3587 ) -> f32 {
3588 self.get_width(node_data, node_id, styled_node_state)
3589 .and_then(|w| match w.get_property()? {
3590 LayoutWidth::Px(px) => Some(px.to_pixels_internal(
3591 reference_width,
3592 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3593 )),
3594 _ => Some(0.0), })
3596 .unwrap_or(0.0)
3597 }
3598
3599 pub fn calc_min_width(
3600 &self,
3601 node_data: &NodeData,
3602 node_id: &NodeId,
3603 styled_node_state: &StyledNodeState,
3604 reference_width: f32,
3605 ) -> f32 {
3606 self.get_min_width(node_data, node_id, styled_node_state)
3607 .and_then(|w| {
3608 Some(w.get_property()?.inner.to_pixels_internal(
3609 reference_width,
3610 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3611 ))
3612 })
3613 .unwrap_or(0.0)
3614 }
3615
3616 pub fn calc_max_width(
3617 &self,
3618 node_data: &NodeData,
3619 node_id: &NodeId,
3620 styled_node_state: &StyledNodeState,
3621 reference_width: f32,
3622 ) -> Option<f32> {
3623 self.get_max_width(node_data, node_id, styled_node_state)
3624 .and_then(|w| {
3625 Some(w.get_property()?.inner.to_pixels_internal(
3626 reference_width,
3627 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3628 ))
3629 })
3630 }
3631
3632 pub fn calc_height(
3634 &self,
3635 node_data: &NodeData,
3636 node_id: &NodeId,
3637 styled_node_state: &StyledNodeState,
3638 reference_height: f32,
3639 ) -> f32 {
3640 self.get_height(node_data, node_id, styled_node_state)
3641 .and_then(|h| match h.get_property()? {
3642 LayoutHeight::Px(px) => Some(px.to_pixels_internal(
3643 reference_height,
3644 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3645 )),
3646 _ => Some(0.0), })
3648 .unwrap_or(0.0)
3649 }
3650
3651 pub fn calc_min_height(
3652 &self,
3653 node_data: &NodeData,
3654 node_id: &NodeId,
3655 styled_node_state: &StyledNodeState,
3656 reference_height: f32,
3657 ) -> f32 {
3658 self.get_min_height(node_data, node_id, styled_node_state)
3659 .and_then(|h| {
3660 Some(h.get_property()?.inner.to_pixels_internal(
3661 reference_height,
3662 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3663 ))
3664 })
3665 .unwrap_or(0.0)
3666 }
3667
3668 pub fn calc_max_height(
3669 &self,
3670 node_data: &NodeData,
3671 node_id: &NodeId,
3672 styled_node_state: &StyledNodeState,
3673 reference_height: f32,
3674 ) -> Option<f32> {
3675 self.get_max_height(node_data, node_id, styled_node_state)
3676 .and_then(|h| {
3677 Some(h.get_property()?.inner.to_pixels_internal(
3678 reference_height,
3679 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3680 ))
3681 })
3682 }
3683
3684 pub fn calc_left(
3686 &self,
3687 node_data: &NodeData,
3688 node_id: &NodeId,
3689 styled_node_state: &StyledNodeState,
3690 reference_width: f32,
3691 ) -> Option<f32> {
3692 self.get_left(node_data, node_id, styled_node_state)
3693 .and_then(|l| {
3694 Some(l.get_property()?.inner.to_pixels_internal(
3695 reference_width,
3696 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3697 ))
3698 })
3699 }
3700
3701 pub fn calc_right(
3702 &self,
3703 node_data: &NodeData,
3704 node_id: &NodeId,
3705 styled_node_state: &StyledNodeState,
3706 reference_width: f32,
3707 ) -> Option<f32> {
3708 self.get_right(node_data, node_id, styled_node_state)
3709 .and_then(|r| {
3710 Some(r.get_property()?.inner.to_pixels_internal(
3711 reference_width,
3712 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3713 ))
3714 })
3715 }
3716
3717 pub fn calc_top(
3718 &self,
3719 node_data: &NodeData,
3720 node_id: &NodeId,
3721 styled_node_state: &StyledNodeState,
3722 reference_height: f32,
3723 ) -> Option<f32> {
3724 self.get_top(node_data, node_id, styled_node_state)
3725 .and_then(|t| {
3726 Some(t.get_property()?.inner.to_pixels_internal(
3727 reference_height,
3728 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3729 ))
3730 })
3731 }
3732
3733 pub fn calc_bottom(
3734 &self,
3735 node_data: &NodeData,
3736 node_id: &NodeId,
3737 styled_node_state: &StyledNodeState,
3738 reference_height: f32,
3739 ) -> Option<f32> {
3740 self.get_bottom(node_data, node_id, styled_node_state)
3741 .and_then(|b| {
3742 Some(b.get_property()?.inner.to_pixels_internal(
3743 reference_height,
3744 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3745 ))
3746 })
3747 }
3748
3749 pub fn calc_border_left_width(
3751 &self,
3752 node_data: &NodeData,
3753 node_id: &NodeId,
3754 styled_node_state: &StyledNodeState,
3755 reference_width: f32,
3756 ) -> f32 {
3757 self.get_border_left_width(node_data, node_id, styled_node_state)
3758 .and_then(|b| {
3759 Some(b.get_property()?.inner.to_pixels_internal(
3760 reference_width,
3761 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3762 ))
3763 })
3764 .unwrap_or(0.0)
3765 }
3766
3767 pub fn calc_border_right_width(
3768 &self,
3769 node_data: &NodeData,
3770 node_id: &NodeId,
3771 styled_node_state: &StyledNodeState,
3772 reference_width: f32,
3773 ) -> f32 {
3774 self.get_border_right_width(node_data, node_id, styled_node_state)
3775 .and_then(|b| {
3776 Some(b.get_property()?.inner.to_pixels_internal(
3777 reference_width,
3778 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3779 ))
3780 })
3781 .unwrap_or(0.0)
3782 }
3783
3784 pub fn calc_border_top_width(
3785 &self,
3786 node_data: &NodeData,
3787 node_id: &NodeId,
3788 styled_node_state: &StyledNodeState,
3789 reference_height: f32,
3790 ) -> f32 {
3791 self.get_border_top_width(node_data, node_id, styled_node_state)
3792 .and_then(|b| {
3793 Some(b.get_property()?.inner.to_pixels_internal(
3794 reference_height,
3795 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3796 ))
3797 })
3798 .unwrap_or(0.0)
3799 }
3800
3801 pub fn calc_border_bottom_width(
3802 &self,
3803 node_data: &NodeData,
3804 node_id: &NodeId,
3805 styled_node_state: &StyledNodeState,
3806 reference_height: f32,
3807 ) -> f32 {
3808 self.get_border_bottom_width(node_data, node_id, styled_node_state)
3809 .and_then(|b| {
3810 Some(b.get_property()?.inner.to_pixels_internal(
3811 reference_height,
3812 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3813 ))
3814 })
3815 .unwrap_or(0.0)
3816 }
3817
3818 pub fn calc_padding_left(
3820 &self,
3821 node_data: &NodeData,
3822 node_id: &NodeId,
3823 styled_node_state: &StyledNodeState,
3824 reference_width: f32,
3825 ) -> f32 {
3826 self.get_padding_left(node_data, node_id, styled_node_state)
3827 .and_then(|p| {
3828 Some(p.get_property()?.inner.to_pixels_internal(
3829 reference_width,
3830 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3831 ))
3832 })
3833 .unwrap_or(0.0)
3834 }
3835
3836 pub fn calc_padding_right(
3837 &self,
3838 node_data: &NodeData,
3839 node_id: &NodeId,
3840 styled_node_state: &StyledNodeState,
3841 reference_width: f32,
3842 ) -> f32 {
3843 self.get_padding_right(node_data, node_id, styled_node_state)
3844 .and_then(|p| {
3845 Some(p.get_property()?.inner.to_pixels_internal(
3846 reference_width,
3847 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3848 ))
3849 })
3850 .unwrap_or(0.0)
3851 }
3852
3853 pub fn calc_padding_top(
3854 &self,
3855 node_data: &NodeData,
3856 node_id: &NodeId,
3857 styled_node_state: &StyledNodeState,
3858 reference_height: f32,
3859 ) -> f32 {
3860 self.get_padding_top(node_data, node_id, styled_node_state)
3861 .and_then(|p| {
3862 Some(p.get_property()?.inner.to_pixels_internal(
3863 reference_height,
3864 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3865 ))
3866 })
3867 .unwrap_or(0.0)
3868 }
3869
3870 pub fn calc_padding_bottom(
3871 &self,
3872 node_data: &NodeData,
3873 node_id: &NodeId,
3874 styled_node_state: &StyledNodeState,
3875 reference_height: f32,
3876 ) -> f32 {
3877 self.get_padding_bottom(node_data, node_id, styled_node_state)
3878 .and_then(|p| {
3879 Some(p.get_property()?.inner.to_pixels_internal(
3880 reference_height,
3881 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3882 ))
3883 })
3884 .unwrap_or(0.0)
3885 }
3886
3887 pub fn calc_margin_left(
3889 &self,
3890 node_data: &NodeData,
3891 node_id: &NodeId,
3892 styled_node_state: &StyledNodeState,
3893 reference_width: f32,
3894 ) -> f32 {
3895 self.get_margin_left(node_data, node_id, styled_node_state)
3896 .and_then(|m| {
3897 Some(m.get_property()?.inner.to_pixels_internal(
3898 reference_width,
3899 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3900 ))
3901 })
3902 .unwrap_or(0.0)
3903 }
3904
3905 pub fn calc_margin_right(
3906 &self,
3907 node_data: &NodeData,
3908 node_id: &NodeId,
3909 styled_node_state: &StyledNodeState,
3910 reference_width: f32,
3911 ) -> f32 {
3912 self.get_margin_right(node_data, node_id, styled_node_state)
3913 .and_then(|m| {
3914 Some(m.get_property()?.inner.to_pixels_internal(
3915 reference_width,
3916 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3917 ))
3918 })
3919 .unwrap_or(0.0)
3920 }
3921
3922 pub fn calc_margin_top(
3923 &self,
3924 node_data: &NodeData,
3925 node_id: &NodeId,
3926 styled_node_state: &StyledNodeState,
3927 reference_height: f32,
3928 ) -> f32 {
3929 self.get_margin_top(node_data, node_id, styled_node_state)
3930 .and_then(|m| {
3931 Some(m.get_property()?.inner.to_pixels_internal(
3932 reference_height,
3933 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3934 ))
3935 })
3936 .unwrap_or(0.0)
3937 }
3938
3939 pub fn calc_margin_bottom(
3940 &self,
3941 node_data: &NodeData,
3942 node_id: &NodeId,
3943 styled_node_state: &StyledNodeState,
3944 reference_height: f32,
3945 ) -> f32 {
3946 self.get_margin_bottom(node_data, node_id, styled_node_state)
3947 .and_then(|m| {
3948 Some(m.get_property()?.inner.to_pixels_internal(
3949 reference_height,
3950 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3951 ))
3952 })
3953 .unwrap_or(0.0)
3954 }
3955
3956 fn resolve_cascade_keyword(
3994 property: &CssProperty,
3995 property_type: CssPropertyType,
3996 _node_type: &crate::dom::NodeType,
3997 parent_value: Option<&CssProperty>,
3998 ua_value: Option<&'static CssProperty>,
3999 ) -> Option<CssProperty> {
4000 if property_type.is_inheritable() {
4003 return parent_value.cloned().or_else(|| ua_value.cloned());
4004 } else {
4005 return ua_value.cloned();
4006 }
4007 }
4008
4009 fn resolve_property_dependency(
4010 target_property: &CssProperty,
4011 reference_property: &CssProperty,
4012 ) -> Option<CssProperty> {
4013 use azul_css::{
4014 css::CssPropertyValue,
4015 props::{
4016 basic::{font::StyleFontSize, length::SizeMetric, pixel::PixelValue},
4017 layout::*,
4018 style::{SelectionRadius, StyleLetterSpacing, StyleWordSpacing},
4019 },
4020 };
4021
4022 let get_pixel_value = |prop: &CssProperty| -> Option<PixelValue> {
4024 match prop {
4025 CssProperty::FontSize(val) => val.get_property().map(|v| v.inner),
4026 CssProperty::LetterSpacing(val) => val.get_property().map(|v| v.inner),
4027 CssProperty::WordSpacing(val) => val.get_property().map(|v| v.inner),
4028 CssProperty::PaddingLeft(val) => val.get_property().map(|v| v.inner),
4029 CssProperty::PaddingRight(val) => val.get_property().map(|v| v.inner),
4030 CssProperty::PaddingTop(val) => val.get_property().map(|v| v.inner),
4031 CssProperty::PaddingBottom(val) => val.get_property().map(|v| v.inner),
4032 CssProperty::MarginLeft(val) => val.get_property().map(|v| v.inner),
4033 CssProperty::MarginRight(val) => val.get_property().map(|v| v.inner),
4034 CssProperty::MarginTop(val) => val.get_property().map(|v| v.inner),
4035 CssProperty::MarginBottom(val) => val.get_property().map(|v| v.inner),
4036 CssProperty::MinWidth(val) => val.get_property().map(|v| v.inner),
4037 CssProperty::MinHeight(val) => val.get_property().map(|v| v.inner),
4038 CssProperty::MaxWidth(val) => val.get_property().map(|v| v.inner),
4039 CssProperty::MaxHeight(val) => val.get_property().map(|v| v.inner),
4040 CssProperty::SelectionRadius(val) => val.get_property().map(|v| v.inner),
4041 _ => None,
4042 }
4043 };
4044
4045 let target_pixel_value = get_pixel_value(target_property)?;
4046 let reference_pixel_value = get_pixel_value(reference_property)?;
4047
4048 let reference_px = match reference_pixel_value.metric {
4050 SizeMetric::Px => reference_pixel_value.number.get(),
4051 SizeMetric::Pt => reference_pixel_value.number.get() * 1.333333,
4052 SizeMetric::In => reference_pixel_value.number.get() * 96.0,
4053 SizeMetric::Cm => reference_pixel_value.number.get() * 37.7952755906,
4054 SizeMetric::Mm => reference_pixel_value.number.get() * 3.7795275591,
4055 SizeMetric::Em => return None, SizeMetric::Rem => return None, SizeMetric::Percent => return None, SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => return None,
4060 };
4061
4062 let resolved_px = match target_pixel_value.metric {
4064 SizeMetric::Px => target_pixel_value.number.get(),
4065 SizeMetric::Pt => target_pixel_value.number.get() * 1.333333,
4066 SizeMetric::In => target_pixel_value.number.get() * 96.0,
4067 SizeMetric::Cm => target_pixel_value.number.get() * 37.7952755906,
4068 SizeMetric::Mm => target_pixel_value.number.get() * 3.7795275591,
4069 SizeMetric::Em => target_pixel_value.number.get() * reference_px,
4070 SizeMetric::Rem => target_pixel_value.number.get() * reference_px,
4072 SizeMetric::Percent => target_pixel_value.number.get() / 100.0 * reference_px,
4073 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => return None,
4075 };
4076
4077 let resolved_pixel_value = PixelValue::px(resolved_px);
4079
4080 match target_property {
4081 CssProperty::FontSize(_) => Some(CssProperty::FontSize(CssPropertyValue::Exact(
4082 StyleFontSize {
4083 inner: resolved_pixel_value,
4084 },
4085 ))),
4086 CssProperty::LetterSpacing(_) => Some(CssProperty::LetterSpacing(
4087 CssPropertyValue::Exact(StyleLetterSpacing {
4088 inner: resolved_pixel_value,
4089 }),
4090 )),
4091 CssProperty::WordSpacing(_) => Some(CssProperty::WordSpacing(CssPropertyValue::Exact(
4092 StyleWordSpacing {
4093 inner: resolved_pixel_value,
4094 },
4095 ))),
4096 CssProperty::PaddingLeft(_) => Some(CssProperty::PaddingLeft(CssPropertyValue::Exact(
4097 LayoutPaddingLeft {
4098 inner: resolved_pixel_value,
4099 },
4100 ))),
4101 CssProperty::PaddingRight(_) => Some(CssProperty::PaddingRight(
4102 CssPropertyValue::Exact(LayoutPaddingRight {
4103 inner: resolved_pixel_value,
4104 }),
4105 )),
4106 CssProperty::PaddingTop(_) => Some(CssProperty::PaddingTop(CssPropertyValue::Exact(
4107 LayoutPaddingTop {
4108 inner: resolved_pixel_value,
4109 },
4110 ))),
4111 CssProperty::PaddingBottom(_) => Some(CssProperty::PaddingBottom(
4112 CssPropertyValue::Exact(LayoutPaddingBottom {
4113 inner: resolved_pixel_value,
4114 }),
4115 )),
4116 CssProperty::MarginLeft(_) => Some(CssProperty::MarginLeft(CssPropertyValue::Exact(
4117 LayoutMarginLeft {
4118 inner: resolved_pixel_value,
4119 },
4120 ))),
4121 CssProperty::MarginRight(_) => Some(CssProperty::MarginRight(CssPropertyValue::Exact(
4122 LayoutMarginRight {
4123 inner: resolved_pixel_value,
4124 },
4125 ))),
4126 CssProperty::MarginTop(_) => Some(CssProperty::MarginTop(CssPropertyValue::Exact(
4127 LayoutMarginTop {
4128 inner: resolved_pixel_value,
4129 },
4130 ))),
4131 CssProperty::MarginBottom(_) => Some(CssProperty::MarginBottom(
4132 CssPropertyValue::Exact(LayoutMarginBottom {
4133 inner: resolved_pixel_value,
4134 }),
4135 )),
4136 CssProperty::MinWidth(_) => Some(CssProperty::MinWidth(CssPropertyValue::Exact(
4137 LayoutMinWidth {
4138 inner: resolved_pixel_value,
4139 },
4140 ))),
4141 CssProperty::MinHeight(_) => Some(CssProperty::MinHeight(CssPropertyValue::Exact(
4142 LayoutMinHeight {
4143 inner: resolved_pixel_value,
4144 },
4145 ))),
4146 CssProperty::MaxWidth(_) => Some(CssProperty::MaxWidth(CssPropertyValue::Exact(
4147 LayoutMaxWidth {
4148 inner: resolved_pixel_value,
4149 },
4150 ))),
4151 CssProperty::MaxHeight(_) => Some(CssProperty::MaxHeight(CssPropertyValue::Exact(
4152 LayoutMaxHeight {
4153 inner: resolved_pixel_value,
4154 },
4155 ))),
4156 CssProperty::SelectionRadius(_) => Some(CssProperty::SelectionRadius(
4157 CssPropertyValue::Exact(SelectionRadius {
4158 inner: resolved_pixel_value,
4159 }),
4160 )),
4161 _ => None,
4162 }
4163 }
4164
4165 fn build_dependency_chain(
4183 &self,
4184 node_id: NodeId,
4185 parent_id: Option<NodeId>,
4186 property: &CssProperty,
4187 ) -> Option<CssDependencyChain> {
4188 use azul_css::props::basic::{length::SizeMetric, pixel::PixelValue};
4189
4190 let prop_type = property.get_type();
4191
4192 if prop_type != CssPropertyType::FontSize {
4195 return None;
4196 }
4197
4198 let pixel_value = match property {
4200 CssProperty::FontSize(val) => val.get_property().map(|v| &v.inner)?,
4201 _ => return None,
4202 };
4203
4204 let number = pixel_value.number.get();
4205
4206 let source_node = parent_id?;
4208
4209 match pixel_value.metric {
4210 SizeMetric::Px => Some(CssDependencyChain::absolute(prop_type, number)),
4211 SizeMetric::Pt => {
4212 Some(CssDependencyChain::absolute(prop_type, number * 1.333333))
4214 }
4215 SizeMetric::Em => Some(CssDependencyChain::em(prop_type, source_node, number)),
4216 SizeMetric::Rem => {
4217 Some(CssDependencyChain::rem(prop_type, number))
4219 }
4220 SizeMetric::Percent => Some(CssDependencyChain::percent(
4221 prop_type,
4222 source_node,
4223 number / 100.0,
4224 )),
4225 SizeMetric::In => {
4226 Some(CssDependencyChain::absolute(prop_type, number * 96.0))
4228 }
4229 SizeMetric::Cm => {
4230 Some(CssDependencyChain::absolute(
4232 prop_type,
4233 number * 37.7952755906,
4234 ))
4235 }
4236 SizeMetric::Mm => {
4237 Some(CssDependencyChain::absolute(
4239 prop_type,
4240 number * 3.7795275591,
4241 ))
4242 }
4243 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => {
4246 None
4248 }
4249 }
4250 }
4251
4252 pub fn apply_ua_css(&mut self, node_data: &[NodeData]) {
4260 use azul_css::props::property::CssPropertyType;
4261
4262 for (node_index, node) in node_data.iter().enumerate() {
4264 let node_id = NodeId::new(node_index);
4265 let node_type = &node.node_type;
4266
4267 let property_types = [
4270 CssPropertyType::Display,
4271 CssPropertyType::Width,
4272 CssPropertyType::Height,
4273 CssPropertyType::FontSize,
4274 CssPropertyType::FontWeight,
4275 CssPropertyType::FontFamily,
4276 CssPropertyType::MarginTop,
4277 CssPropertyType::MarginBottom,
4278 CssPropertyType::MarginLeft,
4279 CssPropertyType::MarginRight,
4280 CssPropertyType::PaddingTop,
4281 CssPropertyType::PaddingBottom,
4282 CssPropertyType::PaddingLeft,
4283 CssPropertyType::PaddingRight,
4284 ];
4286
4287 for prop_type in &property_types {
4288 if let Some(ua_prop) = crate::ua_css::get_ua_property(node_type, *prop_type) {
4290 let has_inline = node.css_props.iter().any(|p| {
4293 let is_normal = p.apply_if.as_slice().is_empty();
4295 is_normal && p.property.get_type() == *prop_type
4296 });
4297
4298 let has_css = self
4299 .css_normal_props
4300 .get(&node_id)
4301 .map(|map| map.contains_key(prop_type))
4302 .unwrap_or(false);
4303
4304 let has_cascaded = self
4305 .cascaded_normal_props
4306 .get(&node_id)
4307 .map(|map| map.contains_key(prop_type))
4308 .unwrap_or(false);
4309
4310 if !has_inline && !has_css && !has_cascaded {
4312 self.cascaded_normal_props
4313 .entry(node_id)
4314 .or_insert_with(|| BTreeMap::new())
4315 .entry(*prop_type)
4316 .or_insert_with(|| ua_prop.clone());
4317 }
4318 }
4319 }
4320 }
4321 }
4322
4323 pub fn compute_inherited_values(
4329 &mut self,
4330 node_hierarchy: &[NodeHierarchyItem],
4331 node_data: &[NodeData],
4332 ) -> Vec<NodeId> {
4333 node_hierarchy
4334 .iter()
4335 .enumerate()
4336 .filter_map(|(node_index, hierarchy_item)| {
4337 let node_id = NodeId::new(node_index);
4338 let parent_id = hierarchy_item.parent_id();
4339 let parent_computed =
4340 parent_id.and_then(|pid| self.computed_values.get(&pid).cloned());
4341
4342 let mut ctx = InheritanceContext {
4343 node_id,
4344 parent_id,
4345 computed_values: BTreeMap::new(),
4346 dependency_chains: BTreeMap::new(),
4347 };
4348
4349 if let Some(ref parent_values) = parent_computed {
4351 self.inherit_from_parent(&mut ctx, parent_values);
4352 }
4353
4354 self.apply_cascade_properties(
4356 &mut ctx,
4357 node_id,
4358 &parent_computed,
4359 node_data,
4360 node_index,
4361 );
4362
4363 let changed = self.store_if_changed(&ctx);
4365 changed.then_some(node_id)
4366 })
4367 .collect()
4368 }
4369
4370 fn inherit_from_parent(
4372 &self,
4373 ctx: &mut InheritanceContext,
4374 parent_values: &BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4375 ) {
4376 for (prop_type, prop_with_origin) in
4377 parent_values.iter().filter(|(pt, _)| pt.is_inheritable())
4378 {
4379 ctx.computed_values.insert(
4380 *prop_type,
4381 CssPropertyWithOrigin {
4382 property: prop_with_origin.property.clone(),
4383 origin: CssPropertyOrigin::Inherited,
4384 },
4385 );
4386
4387 if *prop_type == CssPropertyType::FontSize {
4389 continue;
4390 }
4391
4392 if let Some(chain) = ctx
4393 .parent_id
4394 .and_then(|pid| self.dependency_chains.get(&pid))
4395 .and_then(|chains| chains.get(prop_type))
4396 {
4397 ctx.dependency_chains.insert(*prop_type, chain.clone());
4398 }
4399 }
4400 }
4401
4402 fn apply_cascade_properties(
4404 &self,
4405 ctx: &mut InheritanceContext,
4406 node_id: NodeId,
4407 parent_computed: &Option<BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
4408 node_data: &[NodeData],
4409 node_index: usize,
4410 ) {
4411 if let Some(cascaded_props) = self.cascaded_normal_props.get(&node_id).cloned() {
4413 for (prop_type, prop) in cascaded_props.iter() {
4414 if self.should_apply_cascaded(&ctx.computed_values, *prop_type, prop) {
4415 self.process_property(ctx, prop, parent_computed);
4416 }
4417 }
4418 }
4419
4420 if let Some(css_props) = self.css_normal_props.get(&node_id) {
4422 for (_, prop) in css_props.iter() {
4423 self.process_property(ctx, prop, parent_computed);
4424 }
4425 }
4426
4427 for inline_prop in node_data[node_index].css_props.iter() {
4429 if inline_prop.apply_if.as_slice().is_empty() {
4431 self.process_property(ctx, &inline_prop.property, parent_computed);
4432 }
4433 }
4434
4435 if let Some(user_props) = self.user_overridden_properties.get(&node_id) {
4437 for (_, prop) in user_props.iter() {
4438 self.process_property(ctx, prop, parent_computed);
4439 }
4440 }
4441 }
4442
4443 fn should_apply_cascaded(
4445 &self,
4446 computed: &BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4447 prop_type: CssPropertyType,
4448 prop: &CssProperty,
4449 ) -> bool {
4450 if prop_type == CssPropertyType::FontSize {
4452 if let Some(existing) = computed.get(&prop_type) {
4453 if existing.origin == CssPropertyOrigin::Inherited
4454 && Self::has_relative_font_size_unit(prop)
4455 {
4456 return false;
4457 }
4458 }
4459 }
4460
4461 match computed.get(&prop_type) {
4462 None => true,
4463 Some(existing) => existing.origin == CssPropertyOrigin::Inherited,
4464 }
4465 }
4466
4467 fn process_property(
4469 &self,
4470 ctx: &mut InheritanceContext,
4471 prop: &CssProperty,
4472 parent_computed: &Option<BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
4473 ) {
4474 let prop_type = prop.get_type();
4475
4476 let resolved = if prop_type == CssPropertyType::FontSize {
4477 self.resolve_font_size_property(prop, parent_computed)
4478 } else {
4479 self.resolve_other_property(prop, &ctx.computed_values)
4480 };
4481
4482 ctx.computed_values.insert(
4483 prop_type,
4484 CssPropertyWithOrigin {
4485 property: resolved.clone(),
4486 origin: CssPropertyOrigin::Own,
4487 },
4488 );
4489
4490 if let Some(chain) = self.build_dependency_chain(ctx.node_id, ctx.parent_id, &resolved) {
4491 ctx.dependency_chains.insert(prop_type, chain);
4492 }
4493 }
4494
4495 fn resolve_font_size_property(
4497 &self,
4498 prop: &CssProperty,
4499 parent_computed: &Option<BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
4500 ) -> CssProperty {
4501 const DEFAULT_FONT_SIZE_PX: f32 = 16.0;
4502
4503 let parent_font_size = parent_computed
4504 .as_ref()
4505 .and_then(|p| p.get(&CssPropertyType::FontSize));
4506
4507 match parent_font_size {
4508 Some(pfs) => Self::resolve_property_dependency(prop, &pfs.property)
4509 .unwrap_or_else(|| Self::resolve_font_size_to_pixels(prop, DEFAULT_FONT_SIZE_PX)),
4510 None => Self::resolve_font_size_to_pixels(prop, DEFAULT_FONT_SIZE_PX),
4511 }
4512 }
4513
4514 fn resolve_other_property(
4516 &self,
4517 prop: &CssProperty,
4518 computed: &BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4519 ) -> CssProperty {
4520 computed
4521 .get(&CssPropertyType::FontSize)
4522 .and_then(|fs| Self::resolve_property_dependency(prop, &fs.property))
4523 .unwrap_or_else(|| prop.clone())
4524 }
4525
4526 fn resolve_font_size_to_pixels(prop: &CssProperty, reference_px: f32) -> CssProperty {
4528 use azul_css::{
4529 css::CssPropertyValue,
4530 props::basic::{font::StyleFontSize, length::SizeMetric, pixel::PixelValue},
4531 };
4532
4533 const DEFAULT_FONT_SIZE_PX: f32 = 16.0;
4534
4535 let CssProperty::FontSize(css_val) = prop else {
4536 return prop.clone();
4537 };
4538
4539 let Some(font_size) = css_val.get_property() else {
4540 return prop.clone();
4541 };
4542
4543 let resolved_px = match font_size.inner.metric {
4544 SizeMetric::Px => font_size.inner.number.get(),
4545 SizeMetric::Pt => font_size.inner.number.get() * 1.333333,
4546 SizeMetric::In => font_size.inner.number.get() * 96.0,
4547 SizeMetric::Cm => font_size.inner.number.get() * 37.7952755906,
4548 SizeMetric::Mm => font_size.inner.number.get() * 3.7795275591,
4549 SizeMetric::Em => font_size.inner.number.get() * reference_px,
4550 SizeMetric::Rem => font_size.inner.number.get() * DEFAULT_FONT_SIZE_PX,
4551 SizeMetric::Percent => font_size.inner.number.get() / 100.0 * reference_px,
4552 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => {
4553 return prop.clone();
4554 }
4555 };
4556
4557 CssProperty::FontSize(CssPropertyValue::Exact(StyleFontSize {
4558 inner: PixelValue::px(resolved_px),
4559 }))
4560 }
4561
4562 fn has_relative_font_size_unit(prop: &CssProperty) -> bool {
4564 use azul_css::props::basic::length::SizeMetric;
4565
4566 let CssProperty::FontSize(css_val) = prop else {
4567 return false;
4568 };
4569
4570 css_val
4571 .get_property()
4572 .map(|fs| {
4573 matches!(
4574 fs.inner.metric,
4575 SizeMetric::Em | SizeMetric::Rem | SizeMetric::Percent
4576 )
4577 })
4578 .unwrap_or(false)
4579 }
4580
4581 fn store_if_changed(&mut self, ctx: &InheritanceContext) -> bool {
4583 let values_changed = self
4584 .computed_values
4585 .get(&ctx.node_id)
4586 .map(|old| old != &ctx.computed_values)
4587 .unwrap_or(true);
4588
4589 let chains_changed = self
4590 .dependency_chains
4591 .get(&ctx.node_id)
4592 .map(|old| old != &ctx.dependency_chains)
4593 .unwrap_or(!ctx.dependency_chains.is_empty());
4594
4595 let changed = values_changed || chains_changed;
4596
4597 self.computed_values
4598 .insert(ctx.node_id, ctx.computed_values.clone());
4599 if !ctx.dependency_chains.is_empty() {
4600 self.dependency_chains
4601 .insert(ctx.node_id, ctx.dependency_chains.clone());
4602 }
4603
4604 changed
4605 }
4606}
4607
4608struct InheritanceContext {
4610 node_id: NodeId,
4611 parent_id: Option<NodeId>,
4612 computed_values: BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4613 dependency_chains: BTreeMap<CssPropertyType, CssDependencyChain>,
4614}
4615
4616impl CssPropertyCache {
4617 pub fn resolve_dependency_chain(
4633 &self,
4634 node_id: NodeId,
4635 property_type: CssPropertyType,
4636 root_font_size: f32,
4637 ) -> Option<f32> {
4638 let chain = self.get_chain(node_id, property_type)?;
4639
4640 if let Some(cached) = chain.cached_pixels {
4641 return Some(cached);
4642 }
4643
4644 chain.steps.clone().iter().try_fold(None, |_, step| {
4645 Some(self.resolve_step(step, property_type, root_font_size))
4646 })?
4647 }
4648
4649 fn get_chain(
4651 &self,
4652 node_id: NodeId,
4653 property_type: CssPropertyType,
4654 ) -> Option<&CssDependencyChain> {
4655 self.dependency_chains
4656 .get(&node_id)
4657 .and_then(|chains| chains.get(&property_type))
4658 }
4659
4660 fn resolve_step(
4662 &self,
4663 step: &CssDependencyChainStep,
4664 property_type: CssPropertyType,
4665 root_font_size: f32,
4666 ) -> Option<f32> {
4667 match step {
4668 CssDependencyChainStep::Absolute { pixels } => Some(*pixels),
4669 CssDependencyChainStep::Percent {
4670 source_node,
4671 factor,
4672 } => {
4673 let source_val = self.get_cached_pixels(*source_node, property_type)?;
4674 Some(source_val * factor)
4675 }
4676 CssDependencyChainStep::Em {
4677 source_node,
4678 factor,
4679 } => {
4680 let font_size = self.get_cached_pixels(*source_node, CssPropertyType::FontSize)?;
4681 Some(font_size * factor)
4682 }
4683 CssDependencyChainStep::Rem { factor } => Some(root_font_size * factor),
4684 }
4685 }
4686
4687 fn get_cached_pixels(&self, node_id: NodeId, property_type: CssPropertyType) -> Option<f32> {
4689 self.get_chain(node_id, property_type)
4690 .and_then(|chain| chain.cached_pixels)
4691 }
4692
4693 pub fn update_property_and_invalidate_dependents(
4711 &mut self,
4712 node_id: NodeId,
4713 property: CssProperty,
4714 node_hierarchy: &[NodeHierarchyItem],
4715 _node_data: &[NodeData],
4716 ) -> Vec<NodeId> {
4717 let prop_type = property.get_type();
4718
4719 self.update_computed_property(node_id, property.clone());
4720 self.rebuild_dependency_chain(node_id, prop_type, &property, node_hierarchy);
4721
4722 let mut affected = self.invalidate_dependents(node_id);
4723 affected.push(node_id);
4724 affected
4725 }
4726
4727 fn update_computed_property(&mut self, node_id: NodeId, property: CssProperty) {
4729 self.computed_values
4730 .entry(node_id)
4731 .or_insert_with(BTreeMap::new)
4732 .insert(
4733 property.get_type(),
4734 CssPropertyWithOrigin {
4735 property,
4736 origin: CssPropertyOrigin::Own,
4737 },
4738 );
4739 }
4740
4741 fn rebuild_dependency_chain(
4743 &mut self,
4744 node_id: NodeId,
4745 prop_type: CssPropertyType,
4746 property: &CssProperty,
4747 node_hierarchy: &[NodeHierarchyItem],
4748 ) {
4749 let parent_id = node_hierarchy
4750 .get(node_id.index())
4751 .and_then(|h| h.parent_id());
4752
4753 if let Some(chain) = self.build_dependency_chain(node_id, parent_id, property) {
4754 self.dependency_chains
4755 .entry(node_id)
4756 .or_insert_with(BTreeMap::new)
4757 .insert(prop_type, chain);
4758 }
4759 }
4760
4761 fn invalidate_dependents(&mut self, node_id: NodeId) -> Vec<NodeId> {
4763 self.dependency_chains
4764 .iter_mut()
4765 .filter_map(|(dep_node_id, chains)| {
4766 let affected = chains.values_mut().any(|chain| {
4767 if chain.depends_on(node_id) {
4768 chain.cached_pixels = None;
4769 true
4770 } else {
4771 false
4772 }
4773 });
4774 affected.then_some(*dep_node_id)
4775 })
4776 .collect()
4777 }
4778}
4779
4780#[cfg(test)]
4781mod tests {
4782 use super::*;
4783 use crate::dom::NodeType;
4784
4785 #[test]
4786 fn test_ua_css_p_tag_properties() {
4787 let cache = CssPropertyCache::empty(1);
4789
4790 let mut node_data = NodeData::create_node(NodeType::P);
4792
4793 let node_id = NodeId::new(0);
4794 let node_state = StyledNodeState::default();
4795
4796 let display = cache.get_display(&node_data, &node_id, &node_state);
4798 assert!(
4799 display.is_some(),
4800 "Expected <p> to have display property from UA CSS"
4801 );
4802 if let Some(d) = display {
4803 if let Some(display_value) = d.get_property() {
4804 assert_eq!(
4805 *display_value,
4806 LayoutDisplay::Block,
4807 "Expected <p> to have display: block, got {:?}",
4808 display_value
4809 );
4810 }
4811 }
4812
4813 let width = cache.get_width(&node_data, &node_id, &node_state);
4817 assert!(
4819 width.is_none(),
4820 "Expected <p> to NOT have explicit width (should be auto), but got {:?}",
4821 width
4822 );
4823
4824 let height = cache.get_height(&node_data, &node_id, &node_state);
4827 println!("Height for <p> tag: {:?}", height);
4828
4829 assert!(
4831 height.is_none(),
4832 "Expected <p> to NOT have explicit height (should be auto), but got {:?}",
4833 height
4834 );
4835 }
4836
4837 #[test]
4838 fn test_ua_css_body_tag_properties() {
4839 let cache = CssPropertyCache::empty(1);
4840
4841 let node_data = NodeData::create_node(NodeType::Body);
4842
4843 let node_id = NodeId::new(0);
4844 let node_state = StyledNodeState::default();
4845
4846 let width = cache.get_width(&node_data, &node_id, &node_state);
4849 assert!(
4851 width.is_none(),
4852 "Expected <body> to NOT have explicit width (should be auto), but got {:?}",
4853 width
4854 );
4855
4856 let height = cache.get_height(&node_data, &node_id, &node_state);
4859 assert!(
4860 height.is_none(),
4861 "<body> should not have explicit height from UA CSS (should be auto)"
4862 );
4863
4864 let margin_top = cache.get_margin_top(&node_data, &node_id, &node_state);
4866 assert!(
4867 margin_top.is_some(),
4868 "Expected <body> to have margin-top from UA CSS"
4869 );
4870 }
4871}