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 StyleTabSizeValue, 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::TabSize($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::GridTemplateAreas($value) => $expr,
364 CssProperty::Gap($value) => $expr,
365 CssProperty::ColumnGap($value) => $expr,
366 CssProperty::RowGap($value) => $expr,
367 CssProperty::Clear($value) => $expr,
368 CssProperty::ScrollbarStyle($value) => $expr,
369 CssProperty::ScrollbarWidth($value) => $expr,
370 CssProperty::ScrollbarColor($value) => $expr,
371 CssProperty::ListStyleType($value) => $expr,
372 CssProperty::ListStylePosition($value) => $expr,
373 CssProperty::Font($value) => $expr,
374 CssProperty::ColumnCount($value) => $expr,
375 CssProperty::ColumnWidth($value) => $expr,
376 CssProperty::ColumnSpan($value) => $expr,
377 CssProperty::ColumnFill($value) => $expr,
378 CssProperty::ColumnRuleStyle($value) => $expr,
379 CssProperty::ColumnRuleWidth($value) => $expr,
380 CssProperty::ColumnRuleColor($value) => $expr,
381 CssProperty::FlowInto($value) => $expr,
382 CssProperty::FlowFrom($value) => $expr,
383 CssProperty::ShapeOutside($value) => $expr,
384 CssProperty::ShapeInside($value) => $expr,
385 CssProperty::ShapeImageThreshold($value) => $expr,
386 CssProperty::ShapeMargin($value) => $expr,
387 CssProperty::ClipPath($value) => $expr,
388 CssProperty::Content($value) => $expr,
389 CssProperty::CounterIncrement($value) => $expr,
390 CssProperty::CounterReset($value) => $expr,
391 CssProperty::StringSet($value) => $expr,
392 CssProperty::Orphans($value) => $expr,
393 CssProperty::Widows($value) => $expr,
394 CssProperty::PageBreakBefore($value) => $expr,
395 CssProperty::PageBreakAfter($value) => $expr,
396 CssProperty::PageBreakInside($value) => $expr,
397 CssProperty::BreakInside($value) => $expr,
398 CssProperty::BoxDecorationBreak($value) => $expr,
399 CssProperty::TableLayout($value) => $expr,
400 CssProperty::BorderCollapse($value) => $expr,
401 CssProperty::BorderSpacing($value) => $expr,
402 CssProperty::CaptionSide($value) => $expr,
403 CssProperty::EmptyCells($value) => $expr,
404 }
405 };
406}
407
408fn get_initial_value(property_type: CssPropertyType) -> Option<CssProperty> {
411 use azul_css::css::CssPropertyValue;
412
413 match property_type {
416 _ => None,
419 }
420}
421
422#[derive(Debug, Default, Clone, PartialEq)]
434pub struct CssPropertyCache {
435 pub node_count: usize,
437
438 pub user_overridden_properties: Vec<BTreeMap<CssPropertyType, CssProperty>>,
440
441 pub cascaded_normal_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
443 pub cascaded_hover_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
444 pub cascaded_active_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
445 pub cascaded_focus_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
446 pub cascaded_dragging_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
447 pub cascaded_drag_over_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
448
449 pub css_normal_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
451 pub css_hover_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
452 pub css_active_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
453 pub css_focus_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
454 pub css_dragging_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
455 pub css_drag_over_props: Vec<BTreeMap<CssPropertyType, CssProperty>>,
456
457 pub computed_values: Vec<BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
459
460 pub dependency_chains: Vec<BTreeMap<CssPropertyType, CssDependencyChain>>,
462
463 pub resolved_cache: Vec<Vec<(CssPropertyType, CssProperty)>>,
465
466 pub compact_cache: Option<azul_css::compact_cache::CompactLayoutCache>,
469}
470
471impl CssPropertyCache {
472 #[must_use]
474 pub fn restyle(
475 &mut self,
476 css: &mut Css,
477 node_data: &NodeDataContainerRef<NodeData>,
478 node_hierarchy: &NodeHierarchyItemVec,
479 non_leaf_nodes: &ParentWithNodeDepthVec,
480 html_tree: &NodeDataContainerRef<CascadeInfo>,
481 ) -> Vec<TagIdToNodeIdMapping> {
482 use azul_css::{
483 css::{CssDeclaration, CssPathPseudoSelector::*},
484 props::layout::LayoutDisplay,
485 };
486
487 let css_is_empty = css.is_empty();
488
489 if !css_is_empty {
490 css.sort_by_specificity();
491
492 macro_rules! filter_rules {($expected_pseudo_selector:expr, $node_id:expr) => {{
493 css
494 .rules() .filter(|rule_block| crate::style::rule_ends_with(&rule_block.path, $expected_pseudo_selector))
496 .filter(|rule_block| crate::style::matches_html_element(
497 &rule_block.path,
498 $node_id,
499 &node_hierarchy.as_container(),
500 &node_data,
501 &html_tree,
502 $expected_pseudo_selector
503 ))
504 .flat_map(|matched_rule| {
506 matched_rule.declarations
507 .iter()
508 .filter_map(move |declaration| {
509 match declaration {
510 CssDeclaration::Static(s) => Some(s),
511 CssDeclaration::Dynamic(_d) => None, }
513 })
514 })
515 .map(|prop| prop.clone())
516 .collect::<Vec<CssProperty>>()
517 }};}
518
519 let css_normal_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
529 .transform_nodeid_multithreaded_optional(|node_id| {
530 let r = filter_rules!(None, node_id);
531 if r.is_empty() {
532 None
533 } else {
534 Some((node_id, r))
535 }
536 });
537
538 let css_hover_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
539 .transform_nodeid_multithreaded_optional(|node_id| {
540 let r = filter_rules!(Some(Hover), node_id);
541 if r.is_empty() {
542 None
543 } else {
544 Some((node_id, r))
545 }
546 });
547
548 let css_active_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
549 .transform_nodeid_multithreaded_optional(|node_id| {
550 let r = filter_rules!(Some(Active), node_id);
551 if r.is_empty() {
552 None
553 } else {
554 Some((node_id, r))
555 }
556 });
557
558 let css_focus_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
559 .transform_nodeid_multithreaded_optional(|node_id| {
560 let r = filter_rules!(Some(Focus), node_id);
561 if r.is_empty() {
562 None
563 } else {
564 Some((node_id, r))
565 }
566 });
567
568 let css_dragging_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
569 .transform_nodeid_multithreaded_optional(|node_id| {
570 let r = filter_rules!(Some(Dragging), node_id);
571 if r.is_empty() {
572 None
573 } else {
574 Some((node_id, r))
575 }
576 });
577
578 let css_drag_over_rules: NodeDataContainer<(NodeId, Vec<CssProperty>)> = node_data
579 .transform_nodeid_multithreaded_optional(|node_id| {
580 let r = filter_rules!(Some(DragOver), node_id);
581 if r.is_empty() {
582 None
583 } else {
584 Some((node_id, r))
585 }
586 });
587
588 macro_rules! assign_css_rules {
590 ($field:expr, $rules:expr) => {{
591 for entry in $field.iter_mut() { entry.clear(); }
592 for (n, map) in $rules.internal.into_iter() {
593 $field[n.index()] = map.into_iter()
594 .map(|prop| (prop.get_type(), prop))
595 .collect();
596 }
597 }};
598 }
599
600 assign_css_rules!(self.css_normal_props, css_normal_rules);
601 assign_css_rules!(self.css_hover_props, css_hover_rules);
602 assign_css_rules!(self.css_active_props, css_active_rules);
603 assign_css_rules!(self.css_focus_props, css_focus_rules);
604 assign_css_rules!(self.css_dragging_props, css_dragging_rules);
605 assign_css_rules!(self.css_drag_over_props, css_drag_over_rules);
606 }
607
608 for ParentWithNodeDepth { depth: _, node_id } in non_leaf_nodes.iter() {
611 let parent_id = match node_id.into_crate_internal() {
612 Some(s) => s,
613 None => continue,
614 };
615
616 macro_rules! inherit_props {
619 ($from_inherit_map:expr, $to_inherit_map:expr) => {
620 let parent_map = &$from_inherit_map[parent_id.index()];
621 if !parent_map.is_empty() {
622 let parent_inherit_props: Vec<(CssPropertyType, CssProperty)> = parent_map
623 .iter()
624 .filter(|(css_prop_type, _)| css_prop_type.is_inheritable())
625 .map(|(css_prop_type, css_prop)| (*css_prop_type, css_prop.clone()))
626 .collect();
627
628 if !parent_inherit_props.is_empty() {
629 for child_id in parent_id.az_children(&node_hierarchy.as_container()) {
632 let child_map = &mut $to_inherit_map[child_id.index()];
633
634 for (inherited_rule_type, inherited_rule_value) in parent_inherit_props.iter() {
635 let _ = child_map
636 .entry(*inherited_rule_type)
637 .or_insert_with(|| inherited_rule_value.clone());
638 }
639 }
640 }
641 }
642 };
643 }
644
645 macro_rules! inherit_inline_css_props {($filter_pseudo_state:expr, $to_inherit_map:expr) => {{
648 let parent_inheritable_css_props = &node_data[parent_id]
649 .css_props
650 .iter()
651 .filter(|css_prop| {
653 let conditions = css_prop.apply_if.as_slice();
655 if conditions.is_empty() {
656 $filter_pseudo_state == PseudoStateType::Normal
658 } else {
659 conditions.iter().all(|c| {
661 matches!(c, DynamicSelector::PseudoState(state) if *state == $filter_pseudo_state)
662 })
663 }
664 })
665 .map(|css_prop| &css_prop.property)
667 .filter(|css_prop| css_prop.get_type().is_inheritable())
669 .cloned()
670 .collect::<Vec<CssProperty>>();
671
672 if !parent_inheritable_css_props.is_empty() {
673 for child_id in parent_id.az_children(&node_hierarchy.as_container()) {
675 let child_map = &mut $to_inherit_map[child_id.index()];
676 for inherited_rule in parent_inheritable_css_props.iter() {
677 let _ = child_map
678 .entry(inherited_rule.get_type())
679 .or_insert_with(|| inherited_rule.clone());
680 }
681 }
682 }
683
684 }};}
685
686 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
687 inherit_inline_css_props!(PseudoStateType::Normal, self.cascaded_normal_props);
691 inherit_inline_css_props!(PseudoStateType::Hover, self.cascaded_hover_props);
692 inherit_inline_css_props!(PseudoStateType::Active, self.cascaded_active_props);
693 inherit_inline_css_props!(PseudoStateType::Focus, self.cascaded_focus_props);
694 inherit_inline_css_props!(PseudoStateType::Dragging, self.cascaded_dragging_props);
695 inherit_inline_css_props!(PseudoStateType::DragOver, self.cascaded_drag_over_props);
696
697 if !css_is_empty {
699 inherit_props!(self.css_normal_props, self.cascaded_normal_props);
700 inherit_props!(self.css_hover_props, self.cascaded_hover_props);
701 inherit_props!(self.css_active_props, self.cascaded_active_props);
702 inherit_props!(self.css_focus_props, self.cascaded_focus_props);
703 inherit_props!(self.css_dragging_props, self.cascaded_dragging_props);
704 inherit_props!(self.css_drag_over_props, self.cascaded_drag_over_props);
705 }
706
707 inherit_props!(self.cascaded_normal_props, self.cascaded_normal_props);
709 inherit_props!(self.cascaded_hover_props, self.cascaded_hover_props);
710 inherit_props!(self.cascaded_active_props, self.cascaded_active_props);
711 inherit_props!(self.cascaded_focus_props, self.cascaded_focus_props);
712 inherit_props!(self.cascaded_dragging_props, self.cascaded_dragging_props);
713 inherit_props!(self.cascaded_drag_over_props, self.cascaded_drag_over_props);
714 }
715
716 let default_node_state = StyledNodeState::default();
719
720 let node_data_container = &node_data.internal;
731
732 node_data
733 .internal
734 .iter()
735 .enumerate()
736 .filter_map(|(node_id, node_data)| {
737 let node_id = NodeId::new(node_id);
738
739 let should_auto_insert_tabindex = node_data
740 .get_callbacks()
741 .iter()
742 .any(|cb| cb.event.is_focus_callback());
743
744 let tab_index = match node_data.get_tab_index() {
745 Some(s) => Some(*s),
746 None => {
747 if should_auto_insert_tabindex {
748 Some(TabIndex::Auto)
749 } else {
750 None
751 }
752 }
753 };
754
755 let mut node_should_have_tag = false;
756
757 loop {
760 let display = self
762 .get_display(&node_data, &node_id, &default_node_state)
763 .and_then(|p| p.get_property_or_default())
764 .unwrap_or_default();
765
766 if display == LayoutDisplay::None {
767 node_should_have_tag = false;
768 break;
769 }
770
771 if node_data.has_context_menu() {
772 node_should_have_tag = true;
773 break;
774 }
775
776 if tab_index.is_some() {
777 node_should_have_tag = true;
778 break;
779 }
780
781 if node_data.get_context_menu().is_some() {
783 node_should_have_tag = true;
784 break;
785 }
786
787 let node_has_hover_props = {
789 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
790 node_data.css_props.as_ref().iter().any(|p| {
791 p.apply_if.as_slice().iter().any(|c| {
792 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Hover))
793 })
794 })
795 } || self.css_hover_props.get(node_id.index()).map_or(false, |m| !m.is_empty())
796 || self.cascaded_hover_props.get(node_id.index()).map_or(false, |m| !m.is_empty());
797
798 if node_has_hover_props {
799 node_should_have_tag = true;
800 break;
801 }
802
803 let node_has_active_props = {
805 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
806 node_data.css_props.as_ref().iter().any(|p| {
807 p.apply_if.as_slice().iter().any(|c| {
808 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Active))
809 })
810 })
811 } || self.css_active_props.get(node_id.index()).map_or(false, |m| !m.is_empty())
812 || self.cascaded_active_props.get(node_id.index()).map_or(false, |m| !m.is_empty());
813
814 if node_has_active_props {
815 node_should_have_tag = true;
816 break;
817 }
818
819 let node_has_focus_props = {
821 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
822 node_data.css_props.as_ref().iter().any(|p| {
823 p.apply_if.as_slice().iter().any(|c| {
824 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Focus))
825 })
826 })
827 } || self.css_focus_props.get(node_id.index()).map_or(false, |m| !m.is_empty())
828 || self.cascaded_focus_props.get(node_id.index()).map_or(false, |m| !m.is_empty());
829
830 if node_has_focus_props {
831 node_should_have_tag = true;
832 break;
833 }
834
835 let node_has_dragging_props = {
837 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
838 node_data.css_props.as_ref().iter().any(|p| {
839 p.apply_if.as_slice().iter().any(|c| {
840 matches!(c, DynamicSelector::PseudoState(PseudoStateType::Dragging))
841 })
842 })
843 } || self.css_dragging_props.get(node_id.index()).map_or(false, |m| !m.is_empty())
844 || self.cascaded_dragging_props.get(node_id.index()).map_or(false, |m| !m.is_empty());
845
846 if node_has_dragging_props {
847 node_should_have_tag = true;
848 break;
849 }
850
851 let node_has_drag_over_props = {
853 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
854 node_data.css_props.as_ref().iter().any(|p| {
855 p.apply_if.as_slice().iter().any(|c| {
856 matches!(c, DynamicSelector::PseudoState(PseudoStateType::DragOver))
857 })
858 })
859 } || self.css_drag_over_props.get(node_id.index()).map_or(false, |m| !m.is_empty())
860 || self.cascaded_drag_over_props.get(node_id.index()).map_or(false, |m| !m.is_empty());
861
862 if node_has_drag_over_props {
863 node_should_have_tag = true;
864 break;
865 }
866
867 let node_only_window_callbacks = node_data.get_callbacks().is_empty()
869 || node_data
870 .get_callbacks()
871 .iter()
872 .all(|cb| cb.event.is_window_callback());
873
874 if !node_only_window_callbacks {
875 node_should_have_tag = true;
876 break;
877 }
878
879 let node_has_non_default_cursor = self
881 .get_cursor(&node_data, &node_id, &default_node_state)
882 .is_some();
883
884 if node_has_non_default_cursor {
885 node_should_have_tag = true;
886 break;
887 }
888
889 let node_has_overflow_scroll = {
893 use azul_css::props::layout::LayoutOverflow;
894 let overflow_x = self
895 .get_overflow_x(&node_data, &node_id, &default_node_state)
896 .and_then(|p| p.get_property_or_default());
897 let overflow_y = self
898 .get_overflow_y(&node_data, &node_id, &default_node_state)
899 .and_then(|p| p.get_property_or_default());
900
901 let x_scrollable = matches!(
902 overflow_x,
903 Some(LayoutOverflow::Scroll | LayoutOverflow::Auto)
904 );
905 let y_scrollable = matches!(
906 overflow_y,
907 Some(LayoutOverflow::Scroll | LayoutOverflow::Auto)
908 );
909 x_scrollable || y_scrollable
910 };
911
912 if node_has_overflow_scroll {
913 node_should_have_tag = true;
914 break;
915 }
916
917 let node_has_selectable_text = {
923 use azul_css::props::style::StyleUserSelect;
924 use crate::dom::NodeType;
925
926 let has_text_children = {
928 let hier = node_hierarchy.as_container()[node_id];
929 let mut has_text = false;
930 if let Some(first_child) = hier.first_child_id(node_id) {
931 let mut child_id = Some(first_child);
932 while let Some(cid) = child_id {
933 let child_data = &node_data_container[cid.index()];
934 if matches!(child_data.get_node_type(), NodeType::Text(_)) {
935 has_text = true;
936 break;
937 }
938 child_id = node_hierarchy.as_container()[cid].next_sibling_id();
939 }
940 }
941 has_text
942 };
943
944 if has_text_children {
945 let user_select = self
947 .get_user_select(&node_data, &node_id, &default_node_state)
948 .and_then(|p| p.get_property().cloned())
949 .unwrap_or(StyleUserSelect::Auto);
950
951 !matches!(user_select, StyleUserSelect::None)
952 } else {
953 false
954 }
955 };
956
957 if node_has_selectable_text {
958 node_should_have_tag = true;
959 break;
960 }
961
962 break;
963 }
964
965 if !node_should_have_tag {
966 None
967 } else {
968 Some(TagIdToNodeIdMapping {
969 tag_id: TagId::from_crate_internal(TagId::unique()),
970 node_id: NodeHierarchyItemId::from_crate_internal(Some(node_id)),
971 tab_index: tab_index.into(),
972 })
973 }
974 })
975 .collect()
976 }
977
978 pub fn get_computed_css_style_string(
979 &self,
980 node_data: &NodeData,
981 node_id: &NodeId,
982 node_state: &StyledNodeState,
983 ) -> String {
984 let mut s = String::new();
985 if let Some(p) = self.get_background_content(&node_data, node_id, node_state) {
986 s.push_str(&format!("background: {};", p.get_css_value_fmt()));
987 }
988 if let Some(p) = self.get_background_position(&node_data, node_id, node_state) {
989 s.push_str(&format!("background-position: {};", p.get_css_value_fmt()));
990 }
991 if let Some(p) = self.get_background_size(&node_data, node_id, node_state) {
992 s.push_str(&format!("background-size: {};", p.get_css_value_fmt()));
993 }
994 if let Some(p) = self.get_background_repeat(&node_data, node_id, node_state) {
995 s.push_str(&format!("background-repeat: {};", p.get_css_value_fmt()));
996 }
997 if let Some(p) = self.get_font_size(&node_data, node_id, node_state) {
998 s.push_str(&format!("font-size: {};", p.get_css_value_fmt()));
999 }
1000 if let Some(p) = self.get_font_family(&node_data, node_id, node_state) {
1001 s.push_str(&format!("font-family: {};", p.get_css_value_fmt()));
1002 }
1003 if let Some(p) = self.get_text_color(&node_data, node_id, node_state) {
1004 s.push_str(&format!("color: {};", p.get_css_value_fmt()));
1005 }
1006 if let Some(p) = self.get_text_align(&node_data, node_id, node_state) {
1007 s.push_str(&format!("text-align: {};", p.get_css_value_fmt()));
1008 }
1009 if let Some(p) = self.get_line_height(&node_data, node_id, node_state) {
1010 s.push_str(&format!("line-height: {};", p.get_css_value_fmt()));
1011 }
1012 if let Some(p) = self.get_letter_spacing(&node_data, node_id, node_state) {
1013 s.push_str(&format!("letter-spacing: {};", p.get_css_value_fmt()));
1014 }
1015 if let Some(p) = self.get_word_spacing(&node_data, node_id, node_state) {
1016 s.push_str(&format!("word-spacing: {};", p.get_css_value_fmt()));
1017 }
1018 if let Some(p) = self.get_tab_size(&node_data, node_id, node_state) {
1019 s.push_str(&format!("tab-size: {};", p.get_css_value_fmt()));
1020 }
1021 if let Some(p) = self.get_cursor(&node_data, node_id, node_state) {
1022 s.push_str(&format!("cursor: {};", p.get_css_value_fmt()));
1023 }
1024 if let Some(p) = self.get_box_shadow_left(&node_data, node_id, node_state) {
1025 s.push_str(&format!(
1026 "-azul-box-shadow-left: {};",
1027 p.get_css_value_fmt()
1028 ));
1029 }
1030 if let Some(p) = self.get_box_shadow_right(&node_data, node_id, node_state) {
1031 s.push_str(&format!(
1032 "-azul-box-shadow-right: {};",
1033 p.get_css_value_fmt()
1034 ));
1035 }
1036 if let Some(p) = self.get_box_shadow_top(&node_data, node_id, node_state) {
1037 s.push_str(&format!("-azul-box-shadow-top: {};", p.get_css_value_fmt()));
1038 }
1039 if let Some(p) = self.get_box_shadow_bottom(&node_data, node_id, node_state) {
1040 s.push_str(&format!(
1041 "-azul-box-shadow-bottom: {};",
1042 p.get_css_value_fmt()
1043 ));
1044 }
1045 if let Some(p) = self.get_border_top_color(&node_data, node_id, node_state) {
1046 s.push_str(&format!("border-top-color: {};", p.get_css_value_fmt()));
1047 }
1048 if let Some(p) = self.get_border_left_color(&node_data, node_id, node_state) {
1049 s.push_str(&format!("border-left-color: {};", p.get_css_value_fmt()));
1050 }
1051 if let Some(p) = self.get_border_right_color(&node_data, node_id, node_state) {
1052 s.push_str(&format!("border-right-color: {};", p.get_css_value_fmt()));
1053 }
1054 if let Some(p) = self.get_border_bottom_color(&node_data, node_id, node_state) {
1055 s.push_str(&format!("border-bottom-color: {};", p.get_css_value_fmt()));
1056 }
1057 if let Some(p) = self.get_border_top_style(&node_data, node_id, node_state) {
1058 s.push_str(&format!("border-top-style: {};", p.get_css_value_fmt()));
1059 }
1060 if let Some(p) = self.get_border_left_style(&node_data, node_id, node_state) {
1061 s.push_str(&format!("border-left-style: {};", p.get_css_value_fmt()));
1062 }
1063 if let Some(p) = self.get_border_right_style(&node_data, node_id, node_state) {
1064 s.push_str(&format!("border-right-style: {};", p.get_css_value_fmt()));
1065 }
1066 if let Some(p) = self.get_border_bottom_style(&node_data, node_id, node_state) {
1067 s.push_str(&format!("border-bottom-style: {};", p.get_css_value_fmt()));
1068 }
1069 if let Some(p) = self.get_border_top_left_radius(&node_data, node_id, node_state) {
1070 s.push_str(&format!(
1071 "border-top-left-radius: {};",
1072 p.get_css_value_fmt()
1073 ));
1074 }
1075 if let Some(p) = self.get_border_top_right_radius(&node_data, node_id, node_state) {
1076 s.push_str(&format!(
1077 "border-top-right-radius: {};",
1078 p.get_css_value_fmt()
1079 ));
1080 }
1081 if let Some(p) = self.get_border_bottom_left_radius(&node_data, node_id, node_state) {
1082 s.push_str(&format!(
1083 "border-bottom-left-radius: {};",
1084 p.get_css_value_fmt()
1085 ));
1086 }
1087 if let Some(p) = self.get_border_bottom_right_radius(&node_data, node_id, node_state) {
1088 s.push_str(&format!(
1089 "border-bottom-right-radius: {};",
1090 p.get_css_value_fmt()
1091 ));
1092 }
1093 if let Some(p) = self.get_opacity(&node_data, node_id, node_state) {
1094 s.push_str(&format!("opacity: {};", p.get_css_value_fmt()));
1095 }
1096 if let Some(p) = self.get_transform(&node_data, node_id, node_state) {
1097 s.push_str(&format!("transform: {};", p.get_css_value_fmt()));
1098 }
1099 if let Some(p) = self.get_transform_origin(&node_data, node_id, node_state) {
1100 s.push_str(&format!("transform-origin: {};", p.get_css_value_fmt()));
1101 }
1102 if let Some(p) = self.get_perspective_origin(&node_data, node_id, node_state) {
1103 s.push_str(&format!("perspective-origin: {};", p.get_css_value_fmt()));
1104 }
1105 if let Some(p) = self.get_backface_visibility(&node_data, node_id, node_state) {
1106 s.push_str(&format!("backface-visibility: {};", p.get_css_value_fmt()));
1107 }
1108 if let Some(p) = self.get_hyphens(&node_data, node_id, node_state) {
1109 s.push_str(&format!("hyphens: {};", p.get_css_value_fmt()));
1110 }
1111 if let Some(p) = self.get_direction(&node_data, node_id, node_state) {
1112 s.push_str(&format!("direction: {};", p.get_css_value_fmt()));
1113 }
1114 if let Some(p) = self.get_white_space(&node_data, node_id, node_state) {
1115 s.push_str(&format!("white-space: {};", p.get_css_value_fmt()));
1116 }
1117 if let Some(p) = self.get_display(&node_data, node_id, node_state) {
1118 s.push_str(&format!("display: {};", p.get_css_value_fmt()));
1119 }
1120 if let Some(p) = self.get_float(&node_data, node_id, node_state) {
1121 s.push_str(&format!("float: {};", p.get_css_value_fmt()));
1122 }
1123 if let Some(p) = self.get_box_sizing(&node_data, node_id, node_state) {
1124 s.push_str(&format!("box-sizing: {};", p.get_css_value_fmt()));
1125 }
1126 if let Some(p) = self.get_width(&node_data, node_id, node_state) {
1127 s.push_str(&format!("width: {};", p.get_css_value_fmt()));
1128 }
1129 if let Some(p) = self.get_height(&node_data, node_id, node_state) {
1130 s.push_str(&format!("height: {};", p.get_css_value_fmt()));
1131 }
1132 if let Some(p) = self.get_min_width(&node_data, node_id, node_state) {
1133 s.push_str(&format!("min-width: {};", p.get_css_value_fmt()));
1134 }
1135 if let Some(p) = self.get_min_height(&node_data, node_id, node_state) {
1136 s.push_str(&format!("min-height: {};", p.get_css_value_fmt()));
1137 }
1138 if let Some(p) = self.get_max_width(&node_data, node_id, node_state) {
1139 s.push_str(&format!("max-width: {};", p.get_css_value_fmt()));
1140 }
1141 if let Some(p) = self.get_max_height(&node_data, node_id, node_state) {
1142 s.push_str(&format!("max-height: {};", p.get_css_value_fmt()));
1143 }
1144 if let Some(p) = self.get_position(&node_data, node_id, node_state) {
1145 s.push_str(&format!("position: {};", p.get_css_value_fmt()));
1146 }
1147 if let Some(p) = self.get_top(&node_data, node_id, node_state) {
1148 s.push_str(&format!("top: {};", p.get_css_value_fmt()));
1149 }
1150 if let Some(p) = self.get_bottom(&node_data, node_id, node_state) {
1151 s.push_str(&format!("bottom: {};", p.get_css_value_fmt()));
1152 }
1153 if let Some(p) = self.get_right(&node_data, node_id, node_state) {
1154 s.push_str(&format!("right: {};", p.get_css_value_fmt()));
1155 }
1156 if let Some(p) = self.get_left(&node_data, node_id, node_state) {
1157 s.push_str(&format!("left: {};", p.get_css_value_fmt()));
1158 }
1159 if let Some(p) = self.get_padding_top(&node_data, node_id, node_state) {
1160 s.push_str(&format!("padding-top: {};", p.get_css_value_fmt()));
1161 }
1162 if let Some(p) = self.get_padding_bottom(&node_data, node_id, node_state) {
1163 s.push_str(&format!("padding-bottom: {};", p.get_css_value_fmt()));
1164 }
1165 if let Some(p) = self.get_padding_left(&node_data, node_id, node_state) {
1166 s.push_str(&format!("padding-left: {};", p.get_css_value_fmt()));
1167 }
1168 if let Some(p) = self.get_padding_right(&node_data, node_id, node_state) {
1169 s.push_str(&format!("padding-right: {};", p.get_css_value_fmt()));
1170 }
1171 if let Some(p) = self.get_margin_top(&node_data, node_id, node_state) {
1172 s.push_str(&format!("margin-top: {};", p.get_css_value_fmt()));
1173 }
1174 if let Some(p) = self.get_margin_bottom(&node_data, node_id, node_state) {
1175 s.push_str(&format!("margin-bottom: {};", p.get_css_value_fmt()));
1176 }
1177 if let Some(p) = self.get_margin_left(&node_data, node_id, node_state) {
1178 s.push_str(&format!("margin-left: {};", p.get_css_value_fmt()));
1179 }
1180 if let Some(p) = self.get_margin_right(&node_data, node_id, node_state) {
1181 s.push_str(&format!("margin-right: {};", p.get_css_value_fmt()));
1182 }
1183 if let Some(p) = self.get_border_top_width(&node_data, node_id, node_state) {
1184 s.push_str(&format!("border-top-width: {};", p.get_css_value_fmt()));
1185 }
1186 if let Some(p) = self.get_border_left_width(&node_data, node_id, node_state) {
1187 s.push_str(&format!("border-left-width: {};", p.get_css_value_fmt()));
1188 }
1189 if let Some(p) = self.get_border_right_width(&node_data, node_id, node_state) {
1190 s.push_str(&format!("border-right-width: {};", p.get_css_value_fmt()));
1191 }
1192 if let Some(p) = self.get_border_bottom_width(&node_data, node_id, node_state) {
1193 s.push_str(&format!("border-bottom-width: {};", p.get_css_value_fmt()));
1194 }
1195 if let Some(p) = self.get_overflow_x(&node_data, node_id, node_state) {
1196 s.push_str(&format!("overflow-x: {};", p.get_css_value_fmt()));
1197 }
1198 if let Some(p) = self.get_overflow_y(&node_data, node_id, node_state) {
1199 s.push_str(&format!("overflow-y: {};", p.get_css_value_fmt()));
1200 }
1201 if let Some(p) = self.get_flex_direction(&node_data, node_id, node_state) {
1202 s.push_str(&format!("flex-direction: {};", p.get_css_value_fmt()));
1203 }
1204 if let Some(p) = self.get_flex_wrap(&node_data, node_id, node_state) {
1205 s.push_str(&format!("flex-wrap: {};", p.get_css_value_fmt()));
1206 }
1207 if let Some(p) = self.get_flex_grow(&node_data, node_id, node_state) {
1208 s.push_str(&format!("flex-grow: {};", p.get_css_value_fmt()));
1209 }
1210 if let Some(p) = self.get_flex_shrink(&node_data, node_id, node_state) {
1211 s.push_str(&format!("flex-shrink: {};", p.get_css_value_fmt()));
1212 }
1213 if let Some(p) = self.get_justify_content(&node_data, node_id, node_state) {
1214 s.push_str(&format!("justify-content: {};", p.get_css_value_fmt()));
1215 }
1216 if let Some(p) = self.get_align_items(&node_data, node_id, node_state) {
1217 s.push_str(&format!("align-items: {};", p.get_css_value_fmt()));
1218 }
1219 if let Some(p) = self.get_align_content(&node_data, node_id, node_state) {
1220 s.push_str(&format!("align-content: {};", p.get_css_value_fmt()));
1221 }
1222 s
1223 }
1224}
1225
1226#[repr(C)]
1227#[derive(Debug, PartialEq, Clone)]
1228pub struct CssPropertyCachePtr {
1229 pub ptr: Box<CssPropertyCache>,
1230 pub run_destructor: bool,
1231}
1232
1233impl CssPropertyCachePtr {
1234 pub fn new(cache: CssPropertyCache) -> Self {
1235 Self {
1236 ptr: Box::new(cache),
1237 run_destructor: true,
1238 }
1239 }
1240 pub fn downcast_mut<'a>(&'a mut self) -> &'a mut CssPropertyCache {
1241 &mut *self.ptr
1242 }
1243}
1244
1245impl Drop for CssPropertyCachePtr {
1246 fn drop(&mut self) {
1247 self.run_destructor = false;
1248 }
1249}
1250
1251impl CssPropertyCache {
1252 pub fn empty(node_count: usize) -> Self {
1253 Self {
1254 node_count,
1255 user_overridden_properties: vec![BTreeMap::new(); node_count],
1256
1257 cascaded_normal_props: vec![BTreeMap::new(); node_count],
1258 cascaded_hover_props: vec![BTreeMap::new(); node_count],
1259 cascaded_active_props: vec![BTreeMap::new(); node_count],
1260 cascaded_focus_props: vec![BTreeMap::new(); node_count],
1261 cascaded_dragging_props: vec![BTreeMap::new(); node_count],
1262 cascaded_drag_over_props: vec![BTreeMap::new(); node_count],
1263
1264 css_normal_props: vec![BTreeMap::new(); node_count],
1265 css_hover_props: vec![BTreeMap::new(); node_count],
1266 css_active_props: vec![BTreeMap::new(); node_count],
1267 css_focus_props: vec![BTreeMap::new(); node_count],
1268 css_dragging_props: vec![BTreeMap::new(); node_count],
1269 css_drag_over_props: vec![BTreeMap::new(); node_count],
1270
1271 computed_values: vec![BTreeMap::new(); node_count],
1272 dependency_chains: vec![BTreeMap::new(); node_count],
1273 resolved_cache: Vec::new(),
1274 compact_cache: None,
1275 }
1276 }
1277
1278 pub fn append(&mut self, other: &mut Self) {
1279 macro_rules! append_css_property_vec {
1280 ($field_name:ident) => {{
1281 self.$field_name.extend(other.$field_name.drain(..));
1282 }};
1283 }
1284
1285 append_css_property_vec!(user_overridden_properties);
1286 append_css_property_vec!(cascaded_normal_props);
1287 append_css_property_vec!(cascaded_hover_props);
1288 append_css_property_vec!(cascaded_active_props);
1289 append_css_property_vec!(cascaded_focus_props);
1290 append_css_property_vec!(cascaded_dragging_props);
1291 append_css_property_vec!(cascaded_drag_over_props);
1292 append_css_property_vec!(css_normal_props);
1293 append_css_property_vec!(css_hover_props);
1294 append_css_property_vec!(css_active_props);
1295 append_css_property_vec!(css_focus_props);
1296 append_css_property_vec!(css_dragging_props);
1297 append_css_property_vec!(css_drag_over_props);
1298 append_css_property_vec!(computed_values);
1299
1300 for mut chains_map in other.dependency_chains.drain(..) {
1302 for (_prop_type, chain) in chains_map.iter_mut() {
1303 for step in chain.steps.iter_mut() {
1304 match step {
1305 CssDependencyChainStep::Em { source_node, .. } => {
1306 *source_node = NodeId::new(source_node.index() + self.node_count);
1307 }
1308 CssDependencyChainStep::Percent { source_node, .. } => {
1309 *source_node = NodeId::new(source_node.index() + self.node_count);
1310 }
1311 _ => {}
1312 }
1313 }
1314 }
1315 self.dependency_chains.push(chains_map);
1316 }
1317
1318 self.node_count += other.node_count;
1319
1320 self.resolved_cache.clear();
1322 }
1323
1324 pub fn is_horizontal_overflow_visible(
1325 &self,
1326 node_data: &NodeData,
1327 node_id: &NodeId,
1328 node_state: &StyledNodeState,
1329 ) -> bool {
1330 self.get_overflow_x(node_data, node_id, node_state)
1331 .and_then(|p| p.get_property_or_default())
1332 .unwrap_or_default()
1333 .is_overflow_visible()
1334 }
1335
1336 pub fn is_vertical_overflow_visible(
1337 &self,
1338 node_data: &NodeData,
1339 node_id: &NodeId,
1340 node_state: &StyledNodeState,
1341 ) -> bool {
1342 self.get_overflow_y(node_data, node_id, node_state)
1343 .and_then(|p| p.get_property_or_default())
1344 .unwrap_or_default()
1345 .is_overflow_visible()
1346 }
1347
1348 pub fn is_horizontal_overflow_hidden(
1349 &self,
1350 node_data: &NodeData,
1351 node_id: &NodeId,
1352 node_state: &StyledNodeState,
1353 ) -> bool {
1354 self.get_overflow_x(node_data, node_id, node_state)
1355 .and_then(|p| p.get_property_or_default())
1356 .unwrap_or_default()
1357 .is_overflow_hidden()
1358 }
1359
1360 pub fn is_vertical_overflow_hidden(
1361 &self,
1362 node_data: &NodeData,
1363 node_id: &NodeId,
1364 node_state: &StyledNodeState,
1365 ) -> bool {
1366 self.get_overflow_y(node_data, node_id, node_state)
1367 .and_then(|p| p.get_property_or_default())
1368 .unwrap_or_default()
1369 .is_overflow_hidden()
1370 }
1371
1372 pub fn get_text_color_or_default(
1373 &self,
1374 node_data: &NodeData,
1375 node_id: &NodeId,
1376 node_state: &StyledNodeState,
1377 ) -> StyleTextColor {
1378 use crate::ui_solver::DEFAULT_TEXT_COLOR;
1379 self.get_text_color(node_data, node_id, node_state)
1380 .and_then(|fs| fs.get_property().cloned())
1381 .unwrap_or(DEFAULT_TEXT_COLOR)
1382 }
1383
1384 pub fn get_font_id_or_default(
1386 &self,
1387 node_data: &NodeData,
1388 node_id: &NodeId,
1389 node_state: &StyledNodeState,
1390 ) -> StyleFontFamilyVec {
1391 use crate::ui_solver::DEFAULT_FONT_ID;
1392 let default_font_id = vec![StyleFontFamily::System(AzString::from_const_str(
1393 DEFAULT_FONT_ID,
1394 ))]
1395 .into();
1396 let font_family_opt = self.get_font_family(node_data, node_id, node_state);
1397
1398 font_family_opt
1399 .as_ref()
1400 .and_then(|family| Some(family.get_property()?.clone()))
1401 .unwrap_or(default_font_id)
1402 }
1403
1404 pub fn get_font_size_or_default(
1405 &self,
1406 node_data: &NodeData,
1407 node_id: &NodeId,
1408 node_state: &StyledNodeState,
1409 ) -> StyleFontSize {
1410 use crate::ui_solver::DEFAULT_FONT_SIZE;
1411 self.get_font_size(node_data, node_id, node_state)
1412 .and_then(|fs| fs.get_property().cloned())
1413 .unwrap_or(DEFAULT_FONT_SIZE)
1414 }
1415
1416 pub fn has_border(
1417 &self,
1418 node_data: &NodeData,
1419 node_id: &NodeId,
1420 node_state: &StyledNodeState,
1421 ) -> bool {
1422 self.get_border_left_width(node_data, node_id, node_state)
1423 .is_some()
1424 || self
1425 .get_border_right_width(node_data, node_id, node_state)
1426 .is_some()
1427 || self
1428 .get_border_top_width(node_data, node_id, node_state)
1429 .is_some()
1430 || self
1431 .get_border_bottom_width(node_data, node_id, node_state)
1432 .is_some()
1433 }
1434
1435 pub fn has_box_shadow(
1436 &self,
1437 node_data: &NodeData,
1438 node_id: &NodeId,
1439 node_state: &StyledNodeState,
1440 ) -> bool {
1441 self.get_box_shadow_left(node_data, node_id, node_state)
1442 .is_some()
1443 || self
1444 .get_box_shadow_right(node_data, node_id, node_state)
1445 .is_some()
1446 || self
1447 .get_box_shadow_top(node_data, node_id, node_state)
1448 .is_some()
1449 || self
1450 .get_box_shadow_bottom(node_data, node_id, node_state)
1451 .is_some()
1452 }
1453
1454 pub fn get_property<'a>(
1455 &'a self,
1456 node_data: &'a NodeData,
1457 node_id: &NodeId,
1458 node_state: &StyledNodeState,
1459 css_property_type: &CssPropertyType,
1460 ) -> Option<&CssProperty> {
1461 if let Some(node_props) = self.resolved_cache.get(node_id.index()) {
1463 return node_props
1464 .binary_search_by_key(css_property_type, |(t, _)| *t)
1465 .ok()
1466 .map(|i| &node_props[i].1);
1467 }
1468
1469 self.get_property_slow(node_data, node_id, node_state, css_property_type)
1471 }
1472
1473 fn get_property_slow<'a>(
1476 &'a self,
1477 node_data: &'a NodeData,
1478 node_id: &NodeId,
1479 node_state: &StyledNodeState,
1480 css_property_type: &CssPropertyType,
1481 ) -> Option<&CssProperty> {
1482
1483 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
1484
1485 if let Some(p) = self
1487 .user_overridden_properties
1488 .get(node_id.index())
1489 .and_then(|n| n.get(css_property_type))
1490 {
1491 return Some(p);
1492 }
1493
1494 fn matches_pseudo_state(
1496 prop: &azul_css::dynamic_selector::CssPropertyWithConditions,
1497 state: PseudoStateType,
1498 ) -> bool {
1499 let conditions = prop.apply_if.as_slice();
1500 if conditions.is_empty() {
1501 state == PseudoStateType::Normal
1502 } else {
1503 conditions
1504 .iter()
1505 .all(|c| matches!(c, DynamicSelector::PseudoState(s) if *s == state))
1506 }
1507 }
1508
1509 if node_state.focused {
1512 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1514 if matches_pseudo_state(css_prop, PseudoStateType::Focus)
1515 && css_prop.property.get_type() == *css_property_type
1516 {
1517 Some(&css_prop.property)
1518 } else {
1519 None
1520 }
1521 }) {
1522 return Some(p);
1523 }
1524
1525 if let Some(p) = self
1527 .css_focus_props
1528 .get(node_id.index())
1529 .and_then(|map| map.get(css_property_type))
1530 {
1531 return Some(p);
1532 }
1533
1534 if let Some(p) = self
1536 .cascaded_focus_props
1537 .get(node_id.index())
1538 .and_then(|map| map.get(css_property_type))
1539 {
1540 return Some(p);
1541 }
1542 }
1543
1544 if node_state.active {
1545 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1547 if matches_pseudo_state(css_prop, PseudoStateType::Active)
1548 && css_prop.property.get_type() == *css_property_type
1549 {
1550 Some(&css_prop.property)
1551 } else {
1552 None
1553 }
1554 }) {
1555 return Some(p);
1556 }
1557
1558 if let Some(p) = self
1560 .css_active_props
1561 .get(node_id.index())
1562 .and_then(|map| map.get(css_property_type))
1563 {
1564 return Some(p);
1565 }
1566
1567 if let Some(p) = self
1569 .cascaded_active_props
1570 .get(node_id.index())
1571 .and_then(|map| map.get(css_property_type))
1572 {
1573 return Some(p);
1574 }
1575 }
1576
1577 if node_state.dragging {
1579 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1580 if matches_pseudo_state(css_prop, PseudoStateType::Dragging)
1581 && css_prop.property.get_type() == *css_property_type
1582 {
1583 Some(&css_prop.property)
1584 } else {
1585 None
1586 }
1587 }) {
1588 return Some(p);
1589 }
1590
1591 if let Some(p) = self
1592 .css_dragging_props
1593 .get(node_id.index())
1594 .and_then(|map| map.get(css_property_type))
1595 {
1596 return Some(p);
1597 }
1598
1599 if let Some(p) = self
1600 .cascaded_dragging_props
1601 .get(node_id.index())
1602 .and_then(|map| map.get(css_property_type))
1603 {
1604 return Some(p);
1605 }
1606 }
1607
1608 if node_state.drag_over {
1610 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1611 if matches_pseudo_state(css_prop, PseudoStateType::DragOver)
1612 && css_prop.property.get_type() == *css_property_type
1613 {
1614 Some(&css_prop.property)
1615 } else {
1616 None
1617 }
1618 }) {
1619 return Some(p);
1620 }
1621
1622 if let Some(p) = self
1623 .css_drag_over_props
1624 .get(node_id.index())
1625 .and_then(|map| map.get(css_property_type))
1626 {
1627 return Some(p);
1628 }
1629
1630 if let Some(p) = self
1631 .cascaded_drag_over_props
1632 .get(node_id.index())
1633 .and_then(|map| map.get(css_property_type))
1634 {
1635 return Some(p);
1636 }
1637 }
1638
1639 if node_state.hover {
1640 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1642 if matches_pseudo_state(css_prop, PseudoStateType::Hover)
1643 && css_prop.property.get_type() == *css_property_type
1644 {
1645 Some(&css_prop.property)
1646 } else {
1647 None
1648 }
1649 }) {
1650 return Some(p);
1651 }
1652
1653 if let Some(p) = self
1655 .css_hover_props
1656 .get(node_id.index())
1657 .and_then(|map| map.get(css_property_type))
1658 {
1659 return Some(p);
1660 }
1661
1662 if let Some(p) = self
1664 .cascaded_hover_props
1665 .get(node_id.index())
1666 .and_then(|map| map.get(css_property_type))
1667 {
1668 return Some(p);
1669 }
1670 }
1671
1672 if let Some(p) = node_data.css_props.as_ref().iter().find_map(|css_prop| {
1675 if matches_pseudo_state(css_prop, PseudoStateType::Normal)
1676 && css_prop.property.get_type() == *css_property_type
1677 {
1678 Some(&css_prop.property)
1679 } else {
1680 None
1681 }
1682 }) {
1683 return Some(p);
1684 }
1685
1686 if let Some(p) = self
1688 .css_normal_props
1689 .get(node_id.index())
1690 .and_then(|map| map.get(css_property_type))
1691 {
1692 return Some(p);
1693 }
1694
1695 if let Some(p) = self
1697 .cascaded_normal_props
1698 .get(node_id.index())
1699 .and_then(|map| map.get(css_property_type))
1700 {
1701 return Some(p);
1702 }
1703
1704 if css_property_type.is_inheritable() {
1708 if let Some(prop_with_origin) = self
1709 .computed_values
1710 .get(node_id.index())
1711 .and_then(|map| map.get(css_property_type))
1712 {
1713 return Some(&prop_with_origin.property);
1714 }
1715 }
1716
1717 crate::ua_css::get_ua_property(&node_data.node_type, *css_property_type)
1720 }
1721
1722 pub fn get_property_with_context<'a>(
1730 &'a self,
1731 node_data: &'a NodeData,
1732 node_id: &NodeId,
1733 context: &DynamicSelectorContext,
1734 css_property_type: &CssPropertyType,
1735 ) -> Option<&CssProperty> {
1736 if let Some(p) = self
1738 .user_overridden_properties
1739 .get(node_id.index())
1740 .and_then(|n| n.get(css_property_type))
1741 {
1742 return Some(p);
1743 }
1744
1745 if let Some(prop_with_conditions) =
1749 node_data.css_props.as_ref().iter().rev().find(|prop| {
1750 prop.property.get_type() == *css_property_type && prop.matches(context)
1751 })
1752 {
1753 return Some(&prop_with_conditions.property);
1754 }
1755
1756 let legacy_state = StyledNodeState::from_pseudo_state_flags(&context.pseudo_state);
1758 if let Some(p) = self.get_property(node_data, node_id, &legacy_state, css_property_type) {
1759 return Some(p);
1760 }
1761
1762 None
1763 }
1764
1765 pub fn check_properties_changed(
1768 node_data: &NodeData,
1769 old_context: &DynamicSelectorContext,
1770 new_context: &DynamicSelectorContext,
1771 ) -> bool {
1772 for prop in node_data.css_props.as_ref().iter() {
1773 let was_active = prop.matches(old_context);
1774 let is_active = prop.matches(new_context);
1775 if was_active != is_active {
1776 return true;
1777 }
1778 }
1779 false
1780 }
1781
1782 pub fn check_layout_properties_changed(
1785 node_data: &NodeData,
1786 old_context: &DynamicSelectorContext,
1787 new_context: &DynamicSelectorContext,
1788 ) -> bool {
1789 for prop in node_data.css_props.as_ref().iter() {
1790 if !prop.is_layout_affecting() {
1792 continue;
1793 }
1794
1795 let was_active = prop.matches(old_context);
1796 let is_active = prop.matches(new_context);
1797 if was_active != is_active {
1798 return true;
1799 }
1800 }
1801 false
1802 }
1803
1804 pub fn get_background_content<'a>(
1805 &'a self,
1806 node_data: &'a NodeData,
1807 node_id: &NodeId,
1808 node_state: &StyledNodeState,
1809 ) -> Option<&'a StyleBackgroundContentVecValue> {
1810 self.get_property(
1811 node_data,
1812 node_id,
1813 node_state,
1814 &CssPropertyType::BackgroundContent,
1815 )
1816 .and_then(|p| p.as_background_content())
1817 }
1818
1819 pub fn get_hyphens<'a>(
1821 &'a self,
1822 node_data: &'a NodeData,
1823 node_id: &NodeId,
1824 node_state: &StyledNodeState,
1825 ) -> Option<&'a StyleHyphensValue> {
1826 self.get_property(node_data, node_id, node_state, &CssPropertyType::Hyphens)
1827 .and_then(|p| p.as_hyphens())
1828 }
1829
1830 pub fn get_direction<'a>(
1832 &'a self,
1833 node_data: &'a NodeData,
1834 node_id: &NodeId,
1835 node_state: &StyledNodeState,
1836 ) -> Option<&'a StyleDirectionValue> {
1837 self.get_property(node_data, node_id, node_state, &CssPropertyType::Direction)
1838 .and_then(|p| p.as_direction())
1839 }
1840
1841 pub fn get_white_space<'a>(
1843 &'a self,
1844 node_data: &'a NodeData,
1845 node_id: &NodeId,
1846 node_state: &StyledNodeState,
1847 ) -> Option<&'a StyleWhiteSpaceValue> {
1848 self.get_property(node_data, node_id, node_state, &CssPropertyType::WhiteSpace)
1849 .and_then(|p| p.as_white_space())
1850 }
1851 pub fn get_background_position<'a>(
1852 &'a self,
1853 node_data: &'a NodeData,
1854 node_id: &NodeId,
1855 node_state: &StyledNodeState,
1856 ) -> Option<&'a StyleBackgroundPositionVecValue> {
1857 self.get_property(
1858 node_data,
1859 node_id,
1860 node_state,
1861 &CssPropertyType::BackgroundPosition,
1862 )
1863 .and_then(|p| p.as_background_position())
1864 }
1865 pub fn get_background_size<'a>(
1866 &'a self,
1867 node_data: &'a NodeData,
1868 node_id: &NodeId,
1869 node_state: &StyledNodeState,
1870 ) -> Option<&'a StyleBackgroundSizeVecValue> {
1871 self.get_property(
1872 node_data,
1873 node_id,
1874 node_state,
1875 &CssPropertyType::BackgroundSize,
1876 )
1877 .and_then(|p| p.as_background_size())
1878 }
1879 pub fn get_background_repeat<'a>(
1880 &'a self,
1881 node_data: &'a NodeData,
1882 node_id: &NodeId,
1883 node_state: &StyledNodeState,
1884 ) -> Option<&'a StyleBackgroundRepeatVecValue> {
1885 self.get_property(
1886 node_data,
1887 node_id,
1888 node_state,
1889 &CssPropertyType::BackgroundRepeat,
1890 )
1891 .and_then(|p| p.as_background_repeat())
1892 }
1893 pub fn get_font_size<'a>(
1894 &'a self,
1895 node_data: &'a NodeData,
1896 node_id: &NodeId,
1897 node_state: &StyledNodeState,
1898 ) -> Option<&'a StyleFontSizeValue> {
1899 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontSize)
1900 .and_then(|p| p.as_font_size())
1901 }
1902 pub fn get_font_family<'a>(
1903 &'a self,
1904 node_data: &'a NodeData,
1905 node_id: &NodeId,
1906 node_state: &StyledNodeState,
1907 ) -> Option<&'a StyleFontFamilyVecValue> {
1908 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontFamily)
1909 .and_then(|p| p.as_font_family())
1910 }
1911 pub fn get_font_weight<'a>(
1912 &'a self,
1913 node_data: &'a NodeData,
1914 node_id: &NodeId,
1915 node_state: &StyledNodeState,
1916 ) -> Option<&'a StyleFontWeightValue> {
1917 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontWeight)
1918 .and_then(|p| p.as_font_weight())
1919 }
1920 pub fn get_font_style<'a>(
1921 &'a self,
1922 node_data: &'a NodeData,
1923 node_id: &NodeId,
1924 node_state: &StyledNodeState,
1925 ) -> Option<&'a StyleFontStyleValue> {
1926 self.get_property(node_data, node_id, node_state, &CssPropertyType::FontStyle)
1927 .and_then(|p| p.as_font_style())
1928 }
1929 pub fn get_text_color<'a>(
1930 &'a self,
1931 node_data: &'a NodeData,
1932 node_id: &NodeId,
1933 node_state: &StyledNodeState,
1934 ) -> Option<&'a StyleTextColorValue> {
1935 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextColor)
1936 .and_then(|p| p.as_text_color())
1937 }
1938 pub fn get_text_indent<'a>(
1940 &'a self,
1941 node_data: &'a NodeData,
1942 node_id: &NodeId,
1943 node_state: &StyledNodeState,
1944 ) -> Option<&'a StyleTextIndentValue> {
1945 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextIndent)
1946 .and_then(|p| p.as_text_indent())
1947 }
1948 pub fn get_initial_letter<'a>(
1950 &'a self,
1951 node_data: &'a NodeData,
1952 node_id: &NodeId,
1953 node_state: &StyledNodeState,
1954 ) -> Option<&'a StyleInitialLetterValue> {
1955 self.get_property(
1956 node_data,
1957 node_id,
1958 node_state,
1959 &CssPropertyType::InitialLetter,
1960 )
1961 .and_then(|p| p.as_initial_letter())
1962 }
1963 pub fn get_line_clamp<'a>(
1965 &'a self,
1966 node_data: &'a NodeData,
1967 node_id: &NodeId,
1968 node_state: &StyledNodeState,
1969 ) -> Option<&'a StyleLineClampValue> {
1970 self.get_property(node_data, node_id, node_state, &CssPropertyType::LineClamp)
1971 .and_then(|p| p.as_line_clamp())
1972 }
1973 pub fn get_hanging_punctuation<'a>(
1975 &'a self,
1976 node_data: &'a NodeData,
1977 node_id: &NodeId,
1978 node_state: &StyledNodeState,
1979 ) -> Option<&'a StyleHangingPunctuationValue> {
1980 self.get_property(
1981 node_data,
1982 node_id,
1983 node_state,
1984 &CssPropertyType::HangingPunctuation,
1985 )
1986 .and_then(|p| p.as_hanging_punctuation())
1987 }
1988 pub fn get_text_combine_upright<'a>(
1990 &'a self,
1991 node_data: &'a NodeData,
1992 node_id: &NodeId,
1993 node_state: &StyledNodeState,
1994 ) -> Option<&'a StyleTextCombineUprightValue> {
1995 self.get_property(
1996 node_data,
1997 node_id,
1998 node_state,
1999 &CssPropertyType::TextCombineUpright,
2000 )
2001 .and_then(|p| p.as_text_combine_upright())
2002 }
2003 pub fn get_exclusion_margin<'a>(
2005 &'a self,
2006 node_data: &'a NodeData,
2007 node_id: &NodeId,
2008 node_state: &StyledNodeState,
2009 ) -> Option<&'a StyleExclusionMarginValue> {
2010 self.get_property(
2011 node_data,
2012 node_id,
2013 node_state,
2014 &CssPropertyType::ExclusionMargin,
2015 )
2016 .and_then(|p| p.as_exclusion_margin())
2017 }
2018 pub fn get_hyphenation_language<'a>(
2020 &'a self,
2021 node_data: &'a NodeData,
2022 node_id: &NodeId,
2023 node_state: &StyledNodeState,
2024 ) -> Option<&'a StyleHyphenationLanguageValue> {
2025 self.get_property(
2026 node_data,
2027 node_id,
2028 node_state,
2029 &CssPropertyType::HyphenationLanguage,
2030 )
2031 .and_then(|p| p.as_hyphenation_language())
2032 }
2033 pub fn get_caret_color<'a>(
2035 &'a self,
2036 node_data: &'a NodeData,
2037 node_id: &NodeId,
2038 node_state: &StyledNodeState,
2039 ) -> Option<&'a CaretColorValue> {
2040 self.get_property(node_data, node_id, node_state, &CssPropertyType::CaretColor)
2041 .and_then(|p| p.as_caret_color())
2042 }
2043
2044 pub fn get_caret_width<'a>(
2046 &'a self,
2047 node_data: &'a NodeData,
2048 node_id: &NodeId,
2049 node_state: &StyledNodeState,
2050 ) -> Option<&'a CaretWidthValue> {
2051 self.get_property(node_data, node_id, node_state, &CssPropertyType::CaretWidth)
2052 .and_then(|p| p.as_caret_width())
2053 }
2054
2055 pub fn get_caret_animation_duration<'a>(
2057 &'a self,
2058 node_data: &'a NodeData,
2059 node_id: &NodeId,
2060 node_state: &StyledNodeState,
2061 ) -> Option<&'a CaretAnimationDurationValue> {
2062 self.get_property(
2063 node_data,
2064 node_id,
2065 node_state,
2066 &CssPropertyType::CaretAnimationDuration,
2067 )
2068 .and_then(|p| p.as_caret_animation_duration())
2069 }
2070
2071 pub fn get_selection_background_color<'a>(
2073 &'a self,
2074 node_data: &'a NodeData,
2075 node_id: &NodeId,
2076 node_state: &StyledNodeState,
2077 ) -> Option<&'a SelectionBackgroundColorValue> {
2078 self.get_property(
2079 node_data,
2080 node_id,
2081 node_state,
2082 &CssPropertyType::SelectionBackgroundColor,
2083 )
2084 .and_then(|p| p.as_selection_background_color())
2085 }
2086
2087 pub fn get_selection_color<'a>(
2089 &'a self,
2090 node_data: &'a NodeData,
2091 node_id: &NodeId,
2092 node_state: &StyledNodeState,
2093 ) -> Option<&'a SelectionColorValue> {
2094 self.get_property(
2095 node_data,
2096 node_id,
2097 node_state,
2098 &CssPropertyType::SelectionColor,
2099 )
2100 .and_then(|p| p.as_selection_color())
2101 }
2102
2103 pub fn get_selection_radius<'a>(
2105 &'a self,
2106 node_data: &'a NodeData,
2107 node_id: &NodeId,
2108 node_state: &StyledNodeState,
2109 ) -> Option<&'a SelectionRadiusValue> {
2110 self.get_property(
2111 node_data,
2112 node_id,
2113 node_state,
2114 &CssPropertyType::SelectionRadius,
2115 )
2116 .and_then(|p| p.as_selection_radius())
2117 }
2118
2119 pub fn get_text_justify<'a>(
2121 &'a self,
2122 node_data: &'a NodeData,
2123 node_id: &NodeId,
2124 node_state: &StyledNodeState,
2125 ) -> Option<&'a LayoutTextJustifyValue> {
2126 self.get_property(
2127 node_data,
2128 node_id,
2129 node_state,
2130 &CssPropertyType::TextJustify,
2131 )
2132 .and_then(|p| p.as_text_justify())
2133 }
2134
2135 pub fn get_z_index<'a>(
2137 &'a self,
2138 node_data: &'a NodeData,
2139 node_id: &NodeId,
2140 node_state: &StyledNodeState,
2141 ) -> Option<&'a LayoutZIndexValue> {
2142 self.get_property(node_data, node_id, node_state, &CssPropertyType::ZIndex)
2143 .and_then(|p| p.as_z_index())
2144 }
2145
2146 pub fn get_flex_basis<'a>(
2148 &'a self,
2149 node_data: &'a NodeData,
2150 node_id: &NodeId,
2151 node_state: &StyledNodeState,
2152 ) -> Option<&'a LayoutFlexBasisValue> {
2153 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexBasis)
2154 .and_then(|p| p.as_flex_basis())
2155 }
2156
2157 pub fn get_column_gap<'a>(
2159 &'a self,
2160 node_data: &'a NodeData,
2161 node_id: &NodeId,
2162 node_state: &StyledNodeState,
2163 ) -> Option<&'a LayoutColumnGapValue> {
2164 self.get_property(node_data, node_id, node_state, &CssPropertyType::ColumnGap)
2165 .and_then(|p| p.as_column_gap())
2166 }
2167
2168 pub fn get_row_gap<'a>(
2170 &'a self,
2171 node_data: &'a NodeData,
2172 node_id: &NodeId,
2173 node_state: &StyledNodeState,
2174 ) -> Option<&'a LayoutRowGapValue> {
2175 self.get_property(node_data, node_id, node_state, &CssPropertyType::RowGap)
2176 .and_then(|p| p.as_row_gap())
2177 }
2178
2179 pub fn get_grid_template_columns<'a>(
2181 &'a self,
2182 node_data: &'a NodeData,
2183 node_id: &NodeId,
2184 node_state: &StyledNodeState,
2185 ) -> Option<&'a LayoutGridTemplateColumnsValue> {
2186 self.get_property(
2187 node_data,
2188 node_id,
2189 node_state,
2190 &CssPropertyType::GridTemplateColumns,
2191 )
2192 .and_then(|p| p.as_grid_template_columns())
2193 }
2194
2195 pub fn get_grid_template_rows<'a>(
2197 &'a self,
2198 node_data: &'a NodeData,
2199 node_id: &NodeId,
2200 node_state: &StyledNodeState,
2201 ) -> Option<&'a LayoutGridTemplateRowsValue> {
2202 self.get_property(
2203 node_data,
2204 node_id,
2205 node_state,
2206 &CssPropertyType::GridTemplateRows,
2207 )
2208 .and_then(|p| p.as_grid_template_rows())
2209 }
2210
2211 pub fn get_grid_auto_columns<'a>(
2213 &'a self,
2214 node_data: &'a NodeData,
2215 node_id: &NodeId,
2216 node_state: &StyledNodeState,
2217 ) -> Option<&'a LayoutGridAutoColumnsValue> {
2218 self.get_property(
2219 node_data,
2220 node_id,
2221 node_state,
2222 &CssPropertyType::GridAutoColumns,
2223 )
2224 .and_then(|p| p.as_grid_auto_columns())
2225 }
2226
2227 pub fn get_grid_auto_rows<'a>(
2229 &'a self,
2230 node_data: &'a NodeData,
2231 node_id: &NodeId,
2232 node_state: &StyledNodeState,
2233 ) -> Option<&'a LayoutGridAutoRowsValue> {
2234 self.get_property(
2235 node_data,
2236 node_id,
2237 node_state,
2238 &CssPropertyType::GridAutoRows,
2239 )
2240 .and_then(|p| p.as_grid_auto_rows())
2241 }
2242
2243 pub fn get_grid_column<'a>(
2245 &'a self,
2246 node_data: &'a NodeData,
2247 node_id: &NodeId,
2248 node_state: &StyledNodeState,
2249 ) -> Option<&'a LayoutGridColumnValue> {
2250 self.get_property(node_data, node_id, node_state, &CssPropertyType::GridColumn)
2251 .and_then(|p| p.as_grid_column())
2252 }
2253
2254 pub fn get_grid_row<'a>(
2256 &'a self,
2257 node_data: &'a NodeData,
2258 node_id: &NodeId,
2259 node_state: &StyledNodeState,
2260 ) -> Option<&'a LayoutGridRowValue> {
2261 self.get_property(node_data, node_id, node_state, &CssPropertyType::GridRow)
2262 .and_then(|p| p.as_grid_row())
2263 }
2264
2265 pub fn get_grid_auto_flow<'a>(
2267 &'a self,
2268 node_data: &'a NodeData,
2269 node_id: &NodeId,
2270 node_state: &StyledNodeState,
2271 ) -> Option<&'a LayoutGridAutoFlowValue> {
2272 self.get_property(
2273 node_data,
2274 node_id,
2275 node_state,
2276 &CssPropertyType::GridAutoFlow,
2277 )
2278 .and_then(|p| p.as_grid_auto_flow())
2279 }
2280
2281 pub fn get_justify_self<'a>(
2283 &'a self,
2284 node_data: &'a NodeData,
2285 node_id: &NodeId,
2286 node_state: &StyledNodeState,
2287 ) -> Option<&'a LayoutJustifySelfValue> {
2288 self.get_property(
2289 node_data,
2290 node_id,
2291 node_state,
2292 &CssPropertyType::JustifySelf,
2293 )
2294 .and_then(|p| p.as_justify_self())
2295 }
2296
2297 pub fn get_justify_items<'a>(
2299 &'a self,
2300 node_data: &'a NodeData,
2301 node_id: &NodeId,
2302 node_state: &StyledNodeState,
2303 ) -> Option<&'a LayoutJustifyItemsValue> {
2304 self.get_property(
2305 node_data,
2306 node_id,
2307 node_state,
2308 &CssPropertyType::JustifyItems,
2309 )
2310 .and_then(|p| p.as_justify_items())
2311 }
2312
2313 pub fn get_gap<'a>(
2315 &'a self,
2316 node_data: &'a NodeData,
2317 node_id: &NodeId,
2318 node_state: &StyledNodeState,
2319 ) -> Option<&'a LayoutGapValue> {
2320 self.get_property(node_data, node_id, node_state, &CssPropertyType::Gap)
2321 .and_then(|p| p.as_gap())
2322 }
2323
2324 pub fn get_grid_gap<'a>(
2326 &'a self,
2327 node_data: &'a NodeData,
2328 node_id: &NodeId,
2329 node_state: &StyledNodeState,
2330 ) -> Option<&'a LayoutGapValue> {
2331 self.get_property(node_data, node_id, node_state, &CssPropertyType::GridGap)
2332 .and_then(|p| p.as_grid_gap())
2333 }
2334
2335 pub fn get_align_self<'a>(
2337 &'a self,
2338 node_data: &'a NodeData,
2339 node_id: &NodeId,
2340 node_state: &StyledNodeState,
2341 ) -> Option<&'a LayoutAlignSelfValue> {
2342 self.get_property(node_data, node_id, node_state, &CssPropertyType::AlignSelf)
2343 .and_then(|p| p.as_align_self())
2344 }
2345
2346 pub fn get_font<'a>(
2348 &'a self,
2349 node_data: &'a NodeData,
2350 node_id: &NodeId,
2351 node_state: &StyledNodeState,
2352 ) -> Option<&'a StyleFontValue> {
2353 self.get_property(node_data, node_id, node_state, &CssPropertyType::Font)
2354 .and_then(|p| p.as_font())
2355 }
2356
2357 pub fn get_writing_mode<'a>(
2359 &'a self,
2360 node_data: &'a NodeData,
2361 node_id: &NodeId,
2362 node_state: &StyledNodeState,
2363 ) -> Option<&'a LayoutWritingModeValue> {
2364 self.get_property(
2365 node_data,
2366 node_id,
2367 node_state,
2368 &CssPropertyType::WritingMode,
2369 )
2370 .and_then(|p| p.as_writing_mode())
2371 }
2372
2373 pub fn get_clear<'a>(
2375 &'a self,
2376 node_data: &'a NodeData,
2377 node_id: &NodeId,
2378 node_state: &StyledNodeState,
2379 ) -> Option<&'a LayoutClearValue> {
2380 self.get_property(node_data, node_id, node_state, &CssPropertyType::Clear)
2381 .and_then(|p| p.as_clear())
2382 }
2383
2384 pub fn get_shape_outside<'a>(
2386 &'a self,
2387 node_data: &'a NodeData,
2388 node_id: &NodeId,
2389 node_state: &StyledNodeState,
2390 ) -> Option<&'a ShapeOutsideValue> {
2391 self.get_property(
2392 node_data,
2393 node_id,
2394 node_state,
2395 &CssPropertyType::ShapeOutside,
2396 )
2397 .and_then(|p| p.as_shape_outside())
2398 }
2399
2400 pub fn get_shape_inside<'a>(
2402 &'a self,
2403 node_data: &'a NodeData,
2404 node_id: &NodeId,
2405 node_state: &StyledNodeState,
2406 ) -> Option<&'a ShapeInsideValue> {
2407 self.get_property(
2408 node_data,
2409 node_id,
2410 node_state,
2411 &CssPropertyType::ShapeInside,
2412 )
2413 .and_then(|p| p.as_shape_inside())
2414 }
2415
2416 pub fn get_clip_path<'a>(
2418 &'a self,
2419 node_data: &'a NodeData,
2420 node_id: &NodeId,
2421 node_state: &StyledNodeState,
2422 ) -> Option<&'a ClipPathValue> {
2423 self.get_property(node_data, node_id, node_state, &CssPropertyType::ClipPath)
2424 .and_then(|p| p.as_clip_path())
2425 }
2426
2427 pub fn get_scrollbar_style<'a>(
2429 &'a self,
2430 node_data: &'a NodeData,
2431 node_id: &NodeId,
2432 node_state: &StyledNodeState,
2433 ) -> Option<&'a ScrollbarStyleValue> {
2434 self.get_property(node_data, node_id, node_state, &CssPropertyType::Scrollbar)
2435 .and_then(|p| p.as_scrollbar())
2436 }
2437
2438 pub fn get_scrollbar_width<'a>(
2440 &'a self,
2441 node_data: &'a NodeData,
2442 node_id: &NodeId,
2443 node_state: &StyledNodeState,
2444 ) -> Option<&'a LayoutScrollbarWidthValue> {
2445 self.get_property(
2446 node_data,
2447 node_id,
2448 node_state,
2449 &CssPropertyType::ScrollbarWidth,
2450 )
2451 .and_then(|p| p.as_scrollbar_width())
2452 }
2453
2454 pub fn get_scrollbar_color<'a>(
2456 &'a self,
2457 node_data: &'a NodeData,
2458 node_id: &NodeId,
2459 node_state: &StyledNodeState,
2460 ) -> Option<&'a StyleScrollbarColorValue> {
2461 self.get_property(
2462 node_data,
2463 node_id,
2464 node_state,
2465 &CssPropertyType::ScrollbarColor,
2466 )
2467 .and_then(|p| p.as_scrollbar_color())
2468 }
2469
2470 pub fn get_visibility<'a>(
2472 &'a self,
2473 node_data: &'a NodeData,
2474 node_id: &NodeId,
2475 node_state: &StyledNodeState,
2476 ) -> Option<&'a StyleVisibilityValue> {
2477 self.get_property(node_data, node_id, node_state, &CssPropertyType::Visibility)
2478 .and_then(|p| p.as_visibility())
2479 }
2480
2481 pub fn get_break_before<'a>(
2483 &'a self,
2484 node_data: &'a NodeData,
2485 node_id: &NodeId,
2486 node_state: &StyledNodeState,
2487 ) -> Option<&'a PageBreakValue> {
2488 self.get_property(
2489 node_data,
2490 node_id,
2491 node_state,
2492 &CssPropertyType::BreakBefore,
2493 )
2494 .and_then(|p| p.as_break_before())
2495 }
2496
2497 pub fn get_break_after<'a>(
2499 &'a self,
2500 node_data: &'a NodeData,
2501 node_id: &NodeId,
2502 node_state: &StyledNodeState,
2503 ) -> Option<&'a PageBreakValue> {
2504 self.get_property(node_data, node_id, node_state, &CssPropertyType::BreakAfter)
2505 .and_then(|p| p.as_break_after())
2506 }
2507
2508 pub fn get_break_inside<'a>(
2510 &'a self,
2511 node_data: &'a NodeData,
2512 node_id: &NodeId,
2513 node_state: &StyledNodeState,
2514 ) -> Option<&'a BreakInsideValue> {
2515 self.get_property(
2516 node_data,
2517 node_id,
2518 node_state,
2519 &CssPropertyType::BreakInside,
2520 )
2521 .and_then(|p| p.as_break_inside())
2522 }
2523
2524 pub fn get_orphans<'a>(
2526 &'a self,
2527 node_data: &'a NodeData,
2528 node_id: &NodeId,
2529 node_state: &StyledNodeState,
2530 ) -> Option<&'a OrphansValue> {
2531 self.get_property(node_data, node_id, node_state, &CssPropertyType::Orphans)
2532 .and_then(|p| p.as_orphans())
2533 }
2534
2535 pub fn get_widows<'a>(
2537 &'a self,
2538 node_data: &'a NodeData,
2539 node_id: &NodeId,
2540 node_state: &StyledNodeState,
2541 ) -> Option<&'a WidowsValue> {
2542 self.get_property(node_data, node_id, node_state, &CssPropertyType::Widows)
2543 .and_then(|p| p.as_widows())
2544 }
2545
2546 pub fn get_box_decoration_break<'a>(
2548 &'a self,
2549 node_data: &'a NodeData,
2550 node_id: &NodeId,
2551 node_state: &StyledNodeState,
2552 ) -> Option<&'a BoxDecorationBreakValue> {
2553 self.get_property(
2554 node_data,
2555 node_id,
2556 node_state,
2557 &CssPropertyType::BoxDecorationBreak,
2558 )
2559 .and_then(|p| p.as_box_decoration_break())
2560 }
2561
2562 pub fn get_column_count<'a>(
2564 &'a self,
2565 node_data: &'a NodeData,
2566 node_id: &NodeId,
2567 node_state: &StyledNodeState,
2568 ) -> Option<&'a ColumnCountValue> {
2569 self.get_property(
2570 node_data,
2571 node_id,
2572 node_state,
2573 &CssPropertyType::ColumnCount,
2574 )
2575 .and_then(|p| p.as_column_count())
2576 }
2577
2578 pub fn get_column_width<'a>(
2580 &'a self,
2581 node_data: &'a NodeData,
2582 node_id: &NodeId,
2583 node_state: &StyledNodeState,
2584 ) -> Option<&'a ColumnWidthValue> {
2585 self.get_property(
2586 node_data,
2587 node_id,
2588 node_state,
2589 &CssPropertyType::ColumnWidth,
2590 )
2591 .and_then(|p| p.as_column_width())
2592 }
2593
2594 pub fn get_column_span<'a>(
2596 &'a self,
2597 node_data: &'a NodeData,
2598 node_id: &NodeId,
2599 node_state: &StyledNodeState,
2600 ) -> Option<&'a ColumnSpanValue> {
2601 self.get_property(node_data, node_id, node_state, &CssPropertyType::ColumnSpan)
2602 .and_then(|p| p.as_column_span())
2603 }
2604
2605 pub fn get_column_fill<'a>(
2607 &'a self,
2608 node_data: &'a NodeData,
2609 node_id: &NodeId,
2610 node_state: &StyledNodeState,
2611 ) -> Option<&'a ColumnFillValue> {
2612 self.get_property(node_data, node_id, node_state, &CssPropertyType::ColumnFill)
2613 .and_then(|p| p.as_column_fill())
2614 }
2615
2616 pub fn get_column_rule_width<'a>(
2618 &'a self,
2619 node_data: &'a NodeData,
2620 node_id: &NodeId,
2621 node_state: &StyledNodeState,
2622 ) -> Option<&'a ColumnRuleWidthValue> {
2623 self.get_property(
2624 node_data,
2625 node_id,
2626 node_state,
2627 &CssPropertyType::ColumnRuleWidth,
2628 )
2629 .and_then(|p| p.as_column_rule_width())
2630 }
2631
2632 pub fn get_column_rule_style<'a>(
2634 &'a self,
2635 node_data: &'a NodeData,
2636 node_id: &NodeId,
2637 node_state: &StyledNodeState,
2638 ) -> Option<&'a ColumnRuleStyleValue> {
2639 self.get_property(
2640 node_data,
2641 node_id,
2642 node_state,
2643 &CssPropertyType::ColumnRuleStyle,
2644 )
2645 .and_then(|p| p.as_column_rule_style())
2646 }
2647
2648 pub fn get_column_rule_color<'a>(
2650 &'a self,
2651 node_data: &'a NodeData,
2652 node_id: &NodeId,
2653 node_state: &StyledNodeState,
2654 ) -> Option<&'a ColumnRuleColorValue> {
2655 self.get_property(
2656 node_data,
2657 node_id,
2658 node_state,
2659 &CssPropertyType::ColumnRuleColor,
2660 )
2661 .and_then(|p| p.as_column_rule_color())
2662 }
2663
2664 pub fn get_flow_into<'a>(
2666 &'a self,
2667 node_data: &'a NodeData,
2668 node_id: &NodeId,
2669 node_state: &StyledNodeState,
2670 ) -> Option<&'a FlowIntoValue> {
2671 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlowInto)
2672 .and_then(|p| p.as_flow_into())
2673 }
2674
2675 pub fn get_flow_from<'a>(
2677 &'a self,
2678 node_data: &'a NodeData,
2679 node_id: &NodeId,
2680 node_state: &StyledNodeState,
2681 ) -> Option<&'a FlowFromValue> {
2682 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlowFrom)
2683 .and_then(|p| p.as_flow_from())
2684 }
2685
2686 pub fn get_shape_margin<'a>(
2688 &'a self,
2689 node_data: &'a NodeData,
2690 node_id: &NodeId,
2691 node_state: &StyledNodeState,
2692 ) -> Option<&'a ShapeMarginValue> {
2693 self.get_property(
2694 node_data,
2695 node_id,
2696 node_state,
2697 &CssPropertyType::ShapeMargin,
2698 )
2699 .and_then(|p| p.as_shape_margin())
2700 }
2701
2702 pub fn get_shape_image_threshold<'a>(
2704 &'a self,
2705 node_data: &'a NodeData,
2706 node_id: &NodeId,
2707 node_state: &StyledNodeState,
2708 ) -> Option<&'a ShapeImageThresholdValue> {
2709 self.get_property(
2710 node_data,
2711 node_id,
2712 node_state,
2713 &CssPropertyType::ShapeImageThreshold,
2714 )
2715 .and_then(|p| p.as_shape_image_threshold())
2716 }
2717
2718 pub fn get_content<'a>(
2720 &'a self,
2721 node_data: &'a NodeData,
2722 node_id: &NodeId,
2723 node_state: &StyledNodeState,
2724 ) -> Option<&'a ContentValue> {
2725 self.get_property(node_data, node_id, node_state, &CssPropertyType::Content)
2726 .and_then(|p| p.as_content())
2727 }
2728
2729 pub fn get_counter_reset<'a>(
2731 &'a self,
2732 node_data: &'a NodeData,
2733 node_id: &NodeId,
2734 node_state: &StyledNodeState,
2735 ) -> Option<&'a CounterResetValue> {
2736 self.get_property(
2737 node_data,
2738 node_id,
2739 node_state,
2740 &CssPropertyType::CounterReset,
2741 )
2742 .and_then(|p| p.as_counter_reset())
2743 }
2744
2745 pub fn get_counter_increment<'a>(
2747 &'a self,
2748 node_data: &'a NodeData,
2749 node_id: &NodeId,
2750 node_state: &StyledNodeState,
2751 ) -> Option<&'a CounterIncrementValue> {
2752 self.get_property(
2753 node_data,
2754 node_id,
2755 node_state,
2756 &CssPropertyType::CounterIncrement,
2757 )
2758 .and_then(|p| p.as_counter_increment())
2759 }
2760
2761 pub fn get_string_set<'a>(
2763 &'a self,
2764 node_data: &'a NodeData,
2765 node_id: &NodeId,
2766 node_state: &StyledNodeState,
2767 ) -> Option<&'a StringSetValue> {
2768 self.get_property(node_data, node_id, node_state, &CssPropertyType::StringSet)
2769 .and_then(|p| p.as_string_set())
2770 }
2771 pub fn get_text_align<'a>(
2772 &'a self,
2773 node_data: &'a NodeData,
2774 node_id: &NodeId,
2775 node_state: &StyledNodeState,
2776 ) -> Option<&'a StyleTextAlignValue> {
2777 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextAlign)
2778 .and_then(|p| p.as_text_align())
2779 }
2780 pub fn get_user_select<'a>(
2781 &'a self,
2782 node_data: &'a NodeData,
2783 node_id: &NodeId,
2784 node_state: &StyledNodeState,
2785 ) -> Option<&'a StyleUserSelectValue> {
2786 self.get_property(node_data, node_id, node_state, &CssPropertyType::UserSelect)
2787 .and_then(|p| p.as_user_select())
2788 }
2789 pub fn get_text_decoration<'a>(
2790 &'a self,
2791 node_data: &'a NodeData,
2792 node_id: &NodeId,
2793 node_state: &StyledNodeState,
2794 ) -> Option<&'a StyleTextDecorationValue> {
2795 self.get_property(
2796 node_data,
2797 node_id,
2798 node_state,
2799 &CssPropertyType::TextDecoration,
2800 )
2801 .and_then(|p| p.as_text_decoration())
2802 }
2803 pub fn get_vertical_align<'a>(
2804 &'a self,
2805 node_data: &'a NodeData,
2806 node_id: &NodeId,
2807 node_state: &StyledNodeState,
2808 ) -> Option<&'a StyleVerticalAlignValue> {
2809 self.get_property(
2810 node_data,
2811 node_id,
2812 node_state,
2813 &CssPropertyType::VerticalAlign,
2814 )
2815 .and_then(|p| p.as_vertical_align())
2816 }
2817 pub fn get_line_height<'a>(
2818 &'a self,
2819 node_data: &'a NodeData,
2820 node_id: &NodeId,
2821 node_state: &StyledNodeState,
2822 ) -> Option<&'a StyleLineHeightValue> {
2823 self.get_property(node_data, node_id, node_state, &CssPropertyType::LineHeight)
2824 .and_then(|p| p.as_line_height())
2825 }
2826 pub fn get_letter_spacing<'a>(
2827 &'a self,
2828 node_data: &'a NodeData,
2829 node_id: &NodeId,
2830 node_state: &StyledNodeState,
2831 ) -> Option<&'a StyleLetterSpacingValue> {
2832 self.get_property(
2833 node_data,
2834 node_id,
2835 node_state,
2836 &CssPropertyType::LetterSpacing,
2837 )
2838 .and_then(|p| p.as_letter_spacing())
2839 }
2840 pub fn get_word_spacing<'a>(
2841 &'a self,
2842 node_data: &'a NodeData,
2843 node_id: &NodeId,
2844 node_state: &StyledNodeState,
2845 ) -> Option<&'a StyleWordSpacingValue> {
2846 self.get_property(
2847 node_data,
2848 node_id,
2849 node_state,
2850 &CssPropertyType::WordSpacing,
2851 )
2852 .and_then(|p| p.as_word_spacing())
2853 }
2854 pub fn get_tab_size<'a>(
2855 &'a self,
2856 node_data: &'a NodeData,
2857 node_id: &NodeId,
2858 node_state: &StyledNodeState,
2859 ) -> Option<&'a StyleTabSizeValue> {
2860 self.get_property(node_data, node_id, node_state, &CssPropertyType::TabSize)
2861 .and_then(|p| p.as_tab_size())
2862 }
2863 pub fn get_cursor<'a>(
2864 &'a self,
2865 node_data: &'a NodeData,
2866 node_id: &NodeId,
2867 node_state: &StyledNodeState,
2868 ) -> Option<&'a StyleCursorValue> {
2869 self.get_property(node_data, node_id, node_state, &CssPropertyType::Cursor)
2870 .and_then(|p| p.as_cursor())
2871 }
2872 pub fn get_box_shadow_left<'a>(
2873 &'a self,
2874 node_data: &'a NodeData,
2875 node_id: &NodeId,
2876 node_state: &StyledNodeState,
2877 ) -> Option<&'a StyleBoxShadowValue> {
2878 self.get_property(
2879 node_data,
2880 node_id,
2881 node_state,
2882 &CssPropertyType::BoxShadowLeft,
2883 )
2884 .and_then(|p| p.as_box_shadow_left())
2885 }
2886 pub fn get_box_shadow_right<'a>(
2887 &'a self,
2888 node_data: &'a NodeData,
2889 node_id: &NodeId,
2890 node_state: &StyledNodeState,
2891 ) -> Option<&'a StyleBoxShadowValue> {
2892 self.get_property(
2893 node_data,
2894 node_id,
2895 node_state,
2896 &CssPropertyType::BoxShadowRight,
2897 )
2898 .and_then(|p| p.as_box_shadow_right())
2899 }
2900 pub fn get_box_shadow_top<'a>(
2901 &'a self,
2902 node_data: &'a NodeData,
2903 node_id: &NodeId,
2904 node_state: &StyledNodeState,
2905 ) -> Option<&'a StyleBoxShadowValue> {
2906 self.get_property(
2907 node_data,
2908 node_id,
2909 node_state,
2910 &CssPropertyType::BoxShadowTop,
2911 )
2912 .and_then(|p| p.as_box_shadow_top())
2913 }
2914 pub fn get_box_shadow_bottom<'a>(
2915 &'a self,
2916 node_data: &'a NodeData,
2917 node_id: &NodeId,
2918 node_state: &StyledNodeState,
2919 ) -> Option<&'a StyleBoxShadowValue> {
2920 self.get_property(
2921 node_data,
2922 node_id,
2923 node_state,
2924 &CssPropertyType::BoxShadowBottom,
2925 )
2926 .and_then(|p| p.as_box_shadow_bottom())
2927 }
2928 pub fn get_border_top_color<'a>(
2929 &'a self,
2930 node_data: &'a NodeData,
2931 node_id: &NodeId,
2932 node_state: &StyledNodeState,
2933 ) -> Option<&'a StyleBorderTopColorValue> {
2934 self.get_property(
2935 node_data,
2936 node_id,
2937 node_state,
2938 &CssPropertyType::BorderTopColor,
2939 )
2940 .and_then(|p| p.as_border_top_color())
2941 }
2942 pub fn get_border_left_color<'a>(
2943 &'a self,
2944 node_data: &'a NodeData,
2945 node_id: &NodeId,
2946 node_state: &StyledNodeState,
2947 ) -> Option<&'a StyleBorderLeftColorValue> {
2948 self.get_property(
2949 node_data,
2950 node_id,
2951 node_state,
2952 &CssPropertyType::BorderLeftColor,
2953 )
2954 .and_then(|p| p.as_border_left_color())
2955 }
2956 pub fn get_border_right_color<'a>(
2957 &'a self,
2958 node_data: &'a NodeData,
2959 node_id: &NodeId,
2960 node_state: &StyledNodeState,
2961 ) -> Option<&'a StyleBorderRightColorValue> {
2962 self.get_property(
2963 node_data,
2964 node_id,
2965 node_state,
2966 &CssPropertyType::BorderRightColor,
2967 )
2968 .and_then(|p| p.as_border_right_color())
2969 }
2970 pub fn get_border_bottom_color<'a>(
2971 &'a self,
2972 node_data: &'a NodeData,
2973 node_id: &NodeId,
2974 node_state: &StyledNodeState,
2975 ) -> Option<&'a StyleBorderBottomColorValue> {
2976 self.get_property(
2977 node_data,
2978 node_id,
2979 node_state,
2980 &CssPropertyType::BorderBottomColor,
2981 )
2982 .and_then(|p| p.as_border_bottom_color())
2983 }
2984 pub fn get_border_top_style<'a>(
2985 &'a self,
2986 node_data: &'a NodeData,
2987 node_id: &NodeId,
2988 node_state: &StyledNodeState,
2989 ) -> Option<&'a StyleBorderTopStyleValue> {
2990 self.get_property(
2991 node_data,
2992 node_id,
2993 node_state,
2994 &CssPropertyType::BorderTopStyle,
2995 )
2996 .and_then(|p| p.as_border_top_style())
2997 }
2998 pub fn get_border_left_style<'a>(
2999 &'a self,
3000 node_data: &'a NodeData,
3001 node_id: &NodeId,
3002 node_state: &StyledNodeState,
3003 ) -> Option<&'a StyleBorderLeftStyleValue> {
3004 self.get_property(
3005 node_data,
3006 node_id,
3007 node_state,
3008 &CssPropertyType::BorderLeftStyle,
3009 )
3010 .and_then(|p| p.as_border_left_style())
3011 }
3012 pub fn get_border_right_style<'a>(
3013 &'a self,
3014 node_data: &'a NodeData,
3015 node_id: &NodeId,
3016 node_state: &StyledNodeState,
3017 ) -> Option<&'a StyleBorderRightStyleValue> {
3018 self.get_property(
3019 node_data,
3020 node_id,
3021 node_state,
3022 &CssPropertyType::BorderRightStyle,
3023 )
3024 .and_then(|p| p.as_border_right_style())
3025 }
3026 pub fn get_border_bottom_style<'a>(
3027 &'a self,
3028 node_data: &'a NodeData,
3029 node_id: &NodeId,
3030 node_state: &StyledNodeState,
3031 ) -> Option<&'a StyleBorderBottomStyleValue> {
3032 self.get_property(
3033 node_data,
3034 node_id,
3035 node_state,
3036 &CssPropertyType::BorderBottomStyle,
3037 )
3038 .and_then(|p| p.as_border_bottom_style())
3039 }
3040 pub fn get_border_top_left_radius<'a>(
3041 &'a self,
3042 node_data: &'a NodeData,
3043 node_id: &NodeId,
3044 node_state: &StyledNodeState,
3045 ) -> Option<&'a StyleBorderTopLeftRadiusValue> {
3046 self.get_property(
3047 node_data,
3048 node_id,
3049 node_state,
3050 &CssPropertyType::BorderTopLeftRadius,
3051 )
3052 .and_then(|p| p.as_border_top_left_radius())
3053 }
3054 pub fn get_border_top_right_radius<'a>(
3055 &'a self,
3056 node_data: &'a NodeData,
3057 node_id: &NodeId,
3058 node_state: &StyledNodeState,
3059 ) -> Option<&'a StyleBorderTopRightRadiusValue> {
3060 self.get_property(
3061 node_data,
3062 node_id,
3063 node_state,
3064 &CssPropertyType::BorderTopRightRadius,
3065 )
3066 .and_then(|p| p.as_border_top_right_radius())
3067 }
3068 pub fn get_border_bottom_left_radius<'a>(
3069 &'a self,
3070 node_data: &'a NodeData,
3071 node_id: &NodeId,
3072 node_state: &StyledNodeState,
3073 ) -> Option<&'a StyleBorderBottomLeftRadiusValue> {
3074 self.get_property(
3075 node_data,
3076 node_id,
3077 node_state,
3078 &CssPropertyType::BorderBottomLeftRadius,
3079 )
3080 .and_then(|p| p.as_border_bottom_left_radius())
3081 }
3082 pub fn get_border_bottom_right_radius<'a>(
3083 &'a self,
3084 node_data: &'a NodeData,
3085 node_id: &NodeId,
3086 node_state: &StyledNodeState,
3087 ) -> Option<&'a StyleBorderBottomRightRadiusValue> {
3088 self.get_property(
3089 node_data,
3090 node_id,
3091 node_state,
3092 &CssPropertyType::BorderBottomRightRadius,
3093 )
3094 .and_then(|p| p.as_border_bottom_right_radius())
3095 }
3096 pub fn get_opacity<'a>(
3097 &'a self,
3098 node_data: &'a NodeData,
3099 node_id: &NodeId,
3100 node_state: &StyledNodeState,
3101 ) -> Option<&'a StyleOpacityValue> {
3102 self.get_property(node_data, node_id, node_state, &CssPropertyType::Opacity)
3103 .and_then(|p| p.as_opacity())
3104 }
3105 pub fn get_transform<'a>(
3106 &'a self,
3107 node_data: &'a NodeData,
3108 node_id: &NodeId,
3109 node_state: &StyledNodeState,
3110 ) -> Option<&'a StyleTransformVecValue> {
3111 self.get_property(node_data, node_id, node_state, &CssPropertyType::Transform)
3112 .and_then(|p| p.as_transform())
3113 }
3114 pub fn get_transform_origin<'a>(
3115 &'a self,
3116 node_data: &'a NodeData,
3117 node_id: &NodeId,
3118 node_state: &StyledNodeState,
3119 ) -> Option<&'a StyleTransformOriginValue> {
3120 self.get_property(
3121 node_data,
3122 node_id,
3123 node_state,
3124 &CssPropertyType::TransformOrigin,
3125 )
3126 .and_then(|p| p.as_transform_origin())
3127 }
3128 pub fn get_perspective_origin<'a>(
3129 &'a self,
3130 node_data: &'a NodeData,
3131 node_id: &NodeId,
3132 node_state: &StyledNodeState,
3133 ) -> Option<&'a StylePerspectiveOriginValue> {
3134 self.get_property(
3135 node_data,
3136 node_id,
3137 node_state,
3138 &CssPropertyType::PerspectiveOrigin,
3139 )
3140 .and_then(|p| p.as_perspective_origin())
3141 }
3142 pub fn get_backface_visibility<'a>(
3143 &'a self,
3144 node_data: &'a NodeData,
3145 node_id: &NodeId,
3146 node_state: &StyledNodeState,
3147 ) -> Option<&'a StyleBackfaceVisibilityValue> {
3148 self.get_property(
3149 node_data,
3150 node_id,
3151 node_state,
3152 &CssPropertyType::BackfaceVisibility,
3153 )
3154 .and_then(|p| p.as_backface_visibility())
3155 }
3156 pub fn get_display<'a>(
3157 &'a self,
3158 node_data: &'a NodeData,
3159 node_id: &NodeId,
3160 node_state: &StyledNodeState,
3161 ) -> Option<&'a LayoutDisplayValue> {
3162 self.get_property(node_data, node_id, node_state, &CssPropertyType::Display)
3163 .and_then(|p| p.as_display())
3164 }
3165 pub fn get_float<'a>(
3166 &'a self,
3167 node_data: &'a NodeData,
3168 node_id: &NodeId,
3169 node_state: &StyledNodeState,
3170 ) -> Option<&'a LayoutFloatValue> {
3171 self.get_property(node_data, node_id, node_state, &CssPropertyType::Float)
3172 .and_then(|p| p.as_float())
3173 }
3174 pub fn get_box_sizing<'a>(
3175 &'a self,
3176 node_data: &'a NodeData,
3177 node_id: &NodeId,
3178 node_state: &StyledNodeState,
3179 ) -> Option<&'a LayoutBoxSizingValue> {
3180 self.get_property(node_data, node_id, node_state, &CssPropertyType::BoxSizing)
3181 .and_then(|p| p.as_box_sizing())
3182 }
3183 pub fn get_width<'a>(
3184 &'a self,
3185 node_data: &'a NodeData,
3186 node_id: &NodeId,
3187 node_state: &StyledNodeState,
3188 ) -> Option<&'a LayoutWidthValue> {
3189 self.get_property(node_data, node_id, node_state, &CssPropertyType::Width)
3190 .and_then(|p| p.as_width())
3191 }
3192 pub fn get_height<'a>(
3193 &'a self,
3194 node_data: &'a NodeData,
3195 node_id: &NodeId,
3196 node_state: &StyledNodeState,
3197 ) -> Option<&'a LayoutHeightValue> {
3198 self.get_property(node_data, node_id, node_state, &CssPropertyType::Height)
3199 .and_then(|p| p.as_height())
3200 }
3201 pub fn get_min_width<'a>(
3202 &'a self,
3203 node_data: &'a NodeData,
3204 node_id: &NodeId,
3205 node_state: &StyledNodeState,
3206 ) -> Option<&'a LayoutMinWidthValue> {
3207 self.get_property(node_data, node_id, node_state, &CssPropertyType::MinWidth)
3208 .and_then(|p| p.as_min_width())
3209 }
3210 pub fn get_min_height<'a>(
3211 &'a self,
3212 node_data: &'a NodeData,
3213 node_id: &NodeId,
3214 node_state: &StyledNodeState,
3215 ) -> Option<&'a LayoutMinHeightValue> {
3216 self.get_property(node_data, node_id, node_state, &CssPropertyType::MinHeight)
3217 .and_then(|p| p.as_min_height())
3218 }
3219 pub fn get_max_width<'a>(
3220 &'a self,
3221 node_data: &'a NodeData,
3222 node_id: &NodeId,
3223 node_state: &StyledNodeState,
3224 ) -> Option<&'a LayoutMaxWidthValue> {
3225 self.get_property(node_data, node_id, node_state, &CssPropertyType::MaxWidth)
3226 .and_then(|p| p.as_max_width())
3227 }
3228 pub fn get_max_height<'a>(
3229 &'a self,
3230 node_data: &'a NodeData,
3231 node_id: &NodeId,
3232 node_state: &StyledNodeState,
3233 ) -> Option<&'a LayoutMaxHeightValue> {
3234 self.get_property(node_data, node_id, node_state, &CssPropertyType::MaxHeight)
3235 .and_then(|p| p.as_max_height())
3236 }
3237 pub fn get_position<'a>(
3238 &'a self,
3239 node_data: &'a NodeData,
3240 node_id: &NodeId,
3241 node_state: &StyledNodeState,
3242 ) -> Option<&'a LayoutPositionValue> {
3243 self.get_property(node_data, node_id, node_state, &CssPropertyType::Position)
3244 .and_then(|p| p.as_position())
3245 }
3246 pub fn get_top<'a>(
3247 &'a self,
3248 node_data: &'a NodeData,
3249 node_id: &NodeId,
3250 node_state: &StyledNodeState,
3251 ) -> Option<&'a LayoutTopValue> {
3252 self.get_property(node_data, node_id, node_state, &CssPropertyType::Top)
3253 .and_then(|p| p.as_top())
3254 }
3255 pub fn get_bottom<'a>(
3256 &'a self,
3257 node_data: &'a NodeData,
3258 node_id: &NodeId,
3259 node_state: &StyledNodeState,
3260 ) -> Option<&'a LayoutInsetBottomValue> {
3261 self.get_property(node_data, node_id, node_state, &CssPropertyType::Bottom)
3262 .and_then(|p| p.as_bottom())
3263 }
3264 pub fn get_right<'a>(
3265 &'a self,
3266 node_data: &'a NodeData,
3267 node_id: &NodeId,
3268 node_state: &StyledNodeState,
3269 ) -> Option<&'a LayoutRightValue> {
3270 self.get_property(node_data, node_id, node_state, &CssPropertyType::Right)
3271 .and_then(|p| p.as_right())
3272 }
3273 pub fn get_left<'a>(
3274 &'a self,
3275 node_data: &'a NodeData,
3276 node_id: &NodeId,
3277 node_state: &StyledNodeState,
3278 ) -> Option<&'a LayoutLeftValue> {
3279 self.get_property(node_data, node_id, node_state, &CssPropertyType::Left)
3280 .and_then(|p| p.as_left())
3281 }
3282 pub fn get_padding_top<'a>(
3283 &'a self,
3284 node_data: &'a NodeData,
3285 node_id: &NodeId,
3286 node_state: &StyledNodeState,
3287 ) -> Option<&'a LayoutPaddingTopValue> {
3288 self.get_property(node_data, node_id, node_state, &CssPropertyType::PaddingTop)
3289 .and_then(|p| p.as_padding_top())
3290 }
3291 pub fn get_padding_bottom<'a>(
3292 &'a self,
3293 node_data: &'a NodeData,
3294 node_id: &NodeId,
3295 node_state: &StyledNodeState,
3296 ) -> Option<&'a LayoutPaddingBottomValue> {
3297 self.get_property(
3298 node_data,
3299 node_id,
3300 node_state,
3301 &CssPropertyType::PaddingBottom,
3302 )
3303 .and_then(|p| p.as_padding_bottom())
3304 }
3305 pub fn get_padding_left<'a>(
3306 &'a self,
3307 node_data: &'a NodeData,
3308 node_id: &NodeId,
3309 node_state: &StyledNodeState,
3310 ) -> Option<&'a LayoutPaddingLeftValue> {
3311 self.get_property(
3312 node_data,
3313 node_id,
3314 node_state,
3315 &CssPropertyType::PaddingLeft,
3316 )
3317 .and_then(|p| p.as_padding_left())
3318 }
3319 pub fn get_padding_right<'a>(
3320 &'a self,
3321 node_data: &'a NodeData,
3322 node_id: &NodeId,
3323 node_state: &StyledNodeState,
3324 ) -> Option<&'a LayoutPaddingRightValue> {
3325 self.get_property(
3326 node_data,
3327 node_id,
3328 node_state,
3329 &CssPropertyType::PaddingRight,
3330 )
3331 .and_then(|p| p.as_padding_right())
3332 }
3333 pub fn get_margin_top<'a>(
3334 &'a self,
3335 node_data: &'a NodeData,
3336 node_id: &NodeId,
3337 node_state: &StyledNodeState,
3338 ) -> Option<&'a LayoutMarginTopValue> {
3339 self.get_property(node_data, node_id, node_state, &CssPropertyType::MarginTop)
3340 .and_then(|p| p.as_margin_top())
3341 }
3342 pub fn get_margin_bottom<'a>(
3343 &'a self,
3344 node_data: &'a NodeData,
3345 node_id: &NodeId,
3346 node_state: &StyledNodeState,
3347 ) -> Option<&'a LayoutMarginBottomValue> {
3348 self.get_property(
3349 node_data,
3350 node_id,
3351 node_state,
3352 &CssPropertyType::MarginBottom,
3353 )
3354 .and_then(|p| p.as_margin_bottom())
3355 }
3356 pub fn get_margin_left<'a>(
3357 &'a self,
3358 node_data: &'a NodeData,
3359 node_id: &NodeId,
3360 node_state: &StyledNodeState,
3361 ) -> Option<&'a LayoutMarginLeftValue> {
3362 self.get_property(node_data, node_id, node_state, &CssPropertyType::MarginLeft)
3363 .and_then(|p| p.as_margin_left())
3364 }
3365 pub fn get_margin_right<'a>(
3366 &'a self,
3367 node_data: &'a NodeData,
3368 node_id: &NodeId,
3369 node_state: &StyledNodeState,
3370 ) -> Option<&'a LayoutMarginRightValue> {
3371 self.get_property(
3372 node_data,
3373 node_id,
3374 node_state,
3375 &CssPropertyType::MarginRight,
3376 )
3377 .and_then(|p| p.as_margin_right())
3378 }
3379 pub fn get_border_top_width<'a>(
3380 &'a self,
3381 node_data: &'a NodeData,
3382 node_id: &NodeId,
3383 node_state: &StyledNodeState,
3384 ) -> Option<&'a LayoutBorderTopWidthValue> {
3385 self.get_property(
3386 node_data,
3387 node_id,
3388 node_state,
3389 &CssPropertyType::BorderTopWidth,
3390 )
3391 .and_then(|p| p.as_border_top_width())
3392 }
3393 pub fn get_border_left_width<'a>(
3394 &'a self,
3395 node_data: &'a NodeData,
3396 node_id: &NodeId,
3397 node_state: &StyledNodeState,
3398 ) -> Option<&'a LayoutBorderLeftWidthValue> {
3399 self.get_property(
3400 node_data,
3401 node_id,
3402 node_state,
3403 &CssPropertyType::BorderLeftWidth,
3404 )
3405 .and_then(|p| p.as_border_left_width())
3406 }
3407 pub fn get_border_right_width<'a>(
3408 &'a self,
3409 node_data: &'a NodeData,
3410 node_id: &NodeId,
3411 node_state: &StyledNodeState,
3412 ) -> Option<&'a LayoutBorderRightWidthValue> {
3413 self.get_property(
3414 node_data,
3415 node_id,
3416 node_state,
3417 &CssPropertyType::BorderRightWidth,
3418 )
3419 .and_then(|p| p.as_border_right_width())
3420 }
3421 pub fn get_border_bottom_width<'a>(
3422 &'a self,
3423 node_data: &'a NodeData,
3424 node_id: &NodeId,
3425 node_state: &StyledNodeState,
3426 ) -> Option<&'a LayoutBorderBottomWidthValue> {
3427 self.get_property(
3428 node_data,
3429 node_id,
3430 node_state,
3431 &CssPropertyType::BorderBottomWidth,
3432 )
3433 .and_then(|p| p.as_border_bottom_width())
3434 }
3435 pub fn get_overflow_x<'a>(
3436 &'a self,
3437 node_data: &'a NodeData,
3438 node_id: &NodeId,
3439 node_state: &StyledNodeState,
3440 ) -> Option<&'a LayoutOverflowValue> {
3441 self.get_property(node_data, node_id, node_state, &CssPropertyType::OverflowX)
3442 .and_then(|p| p.as_overflow_x())
3443 }
3444 pub fn get_overflow_y<'a>(
3445 &'a self,
3446 node_data: &'a NodeData,
3447 node_id: &NodeId,
3448 node_state: &StyledNodeState,
3449 ) -> Option<&'a LayoutOverflowValue> {
3450 self.get_property(node_data, node_id, node_state, &CssPropertyType::OverflowY)
3451 .and_then(|p| p.as_overflow_y())
3452 }
3453 pub fn get_flex_direction<'a>(
3454 &'a self,
3455 node_data: &'a NodeData,
3456 node_id: &NodeId,
3457 node_state: &StyledNodeState,
3458 ) -> Option<&'a LayoutFlexDirectionValue> {
3459 self.get_property(
3460 node_data,
3461 node_id,
3462 node_state,
3463 &CssPropertyType::FlexDirection,
3464 )
3465 .and_then(|p| p.as_flex_direction())
3466 }
3467 pub fn get_flex_wrap<'a>(
3468 &'a self,
3469 node_data: &'a NodeData,
3470 node_id: &NodeId,
3471 node_state: &StyledNodeState,
3472 ) -> Option<&'a LayoutFlexWrapValue> {
3473 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexWrap)
3474 .and_then(|p| p.as_flex_wrap())
3475 }
3476 pub fn get_flex_grow<'a>(
3477 &'a self,
3478 node_data: &'a NodeData,
3479 node_id: &NodeId,
3480 node_state: &StyledNodeState,
3481 ) -> Option<&'a LayoutFlexGrowValue> {
3482 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexGrow)
3483 .and_then(|p| p.as_flex_grow())
3484 }
3485 pub fn get_flex_shrink<'a>(
3486 &'a self,
3487 node_data: &'a NodeData,
3488 node_id: &NodeId,
3489 node_state: &StyledNodeState,
3490 ) -> Option<&'a LayoutFlexShrinkValue> {
3491 self.get_property(node_data, node_id, node_state, &CssPropertyType::FlexShrink)
3492 .and_then(|p| p.as_flex_shrink())
3493 }
3494 pub fn get_justify_content<'a>(
3495 &'a self,
3496 node_data: &'a NodeData,
3497 node_id: &NodeId,
3498 node_state: &StyledNodeState,
3499 ) -> Option<&'a LayoutJustifyContentValue> {
3500 self.get_property(
3501 node_data,
3502 node_id,
3503 node_state,
3504 &CssPropertyType::JustifyContent,
3505 )
3506 .and_then(|p| p.as_justify_content())
3507 }
3508 pub fn get_align_items<'a>(
3509 &'a self,
3510 node_data: &'a NodeData,
3511 node_id: &NodeId,
3512 node_state: &StyledNodeState,
3513 ) -> Option<&'a LayoutAlignItemsValue> {
3514 self.get_property(node_data, node_id, node_state, &CssPropertyType::AlignItems)
3515 .and_then(|p| p.as_align_items())
3516 }
3517 pub fn get_align_content<'a>(
3518 &'a self,
3519 node_data: &'a NodeData,
3520 node_id: &NodeId,
3521 node_state: &StyledNodeState,
3522 ) -> Option<&'a LayoutAlignContentValue> {
3523 self.get_property(
3524 node_data,
3525 node_id,
3526 node_state,
3527 &CssPropertyType::AlignContent,
3528 )
3529 .and_then(|p| p.as_align_content())
3530 }
3531 pub fn get_mix_blend_mode<'a>(
3532 &'a self,
3533 node_data: &'a NodeData,
3534 node_id: &NodeId,
3535 node_state: &StyledNodeState,
3536 ) -> Option<&'a StyleMixBlendModeValue> {
3537 self.get_property(
3538 node_data,
3539 node_id,
3540 node_state,
3541 &CssPropertyType::MixBlendMode,
3542 )
3543 .and_then(|p| p.as_mix_blend_mode())
3544 }
3545 pub fn get_filter<'a>(
3546 &'a self,
3547 node_data: &'a NodeData,
3548 node_id: &NodeId,
3549 node_state: &StyledNodeState,
3550 ) -> Option<&'a StyleFilterVecValue> {
3551 self.get_property(node_data, node_id, node_state, &CssPropertyType::Filter)
3552 .and_then(|p| p.as_filter())
3553 }
3554 pub fn get_backdrop_filter<'a>(
3555 &'a self,
3556 node_data: &'a NodeData,
3557 node_id: &NodeId,
3558 node_state: &StyledNodeState,
3559 ) -> Option<&'a StyleFilterVecValue> {
3560 self.get_property(node_data, node_id, node_state, &CssPropertyType::BackdropFilter)
3561 .and_then(|p| p.as_backdrop_filter())
3562 }
3563 pub fn get_text_shadow<'a>(
3564 &'a self,
3565 node_data: &'a NodeData,
3566 node_id: &NodeId,
3567 node_state: &StyledNodeState,
3568 ) -> Option<&'a StyleBoxShadowValue> {
3569 self.get_property(node_data, node_id, node_state, &CssPropertyType::TextShadow)
3570 .and_then(|p| p.as_text_shadow())
3571 }
3572 pub fn get_list_style_type<'a>(
3573 &'a self,
3574 node_data: &'a NodeData,
3575 node_id: &NodeId,
3576 node_state: &StyledNodeState,
3577 ) -> Option<&'a StyleListStyleTypeValue> {
3578 self.get_property(
3579 node_data,
3580 node_id,
3581 node_state,
3582 &CssPropertyType::ListStyleType,
3583 )
3584 .and_then(|p| p.as_list_style_type())
3585 }
3586 pub fn get_list_style_position<'a>(
3587 &'a self,
3588 node_data: &'a NodeData,
3589 node_id: &NodeId,
3590 node_state: &StyledNodeState,
3591 ) -> Option<&'a StyleListStylePositionValue> {
3592 self.get_property(
3593 node_data,
3594 node_id,
3595 node_state,
3596 &CssPropertyType::ListStylePosition,
3597 )
3598 .and_then(|p| p.as_list_style_position())
3599 }
3600 pub fn get_table_layout<'a>(
3601 &'a self,
3602 node_data: &'a NodeData,
3603 node_id: &NodeId,
3604 node_state: &StyledNodeState,
3605 ) -> Option<&'a LayoutTableLayoutValue> {
3606 self.get_property(
3607 node_data,
3608 node_id,
3609 node_state,
3610 &CssPropertyType::TableLayout,
3611 )
3612 .and_then(|p| p.as_table_layout())
3613 }
3614 pub fn get_border_collapse<'a>(
3615 &'a self,
3616 node_data: &'a NodeData,
3617 node_id: &NodeId,
3618 node_state: &StyledNodeState,
3619 ) -> Option<&'a StyleBorderCollapseValue> {
3620 self.get_property(
3621 node_data,
3622 node_id,
3623 node_state,
3624 &CssPropertyType::BorderCollapse,
3625 )
3626 .and_then(|p| p.as_border_collapse())
3627 }
3628 pub fn get_border_spacing<'a>(
3629 &'a self,
3630 node_data: &'a NodeData,
3631 node_id: &NodeId,
3632 node_state: &StyledNodeState,
3633 ) -> Option<&'a LayoutBorderSpacingValue> {
3634 self.get_property(
3635 node_data,
3636 node_id,
3637 node_state,
3638 &CssPropertyType::BorderSpacing,
3639 )
3640 .and_then(|p| p.as_border_spacing())
3641 }
3642 pub fn get_caption_side<'a>(
3643 &'a self,
3644 node_data: &'a NodeData,
3645 node_id: &NodeId,
3646 node_state: &StyledNodeState,
3647 ) -> Option<&'a StyleCaptionSideValue> {
3648 self.get_property(
3649 node_data,
3650 node_id,
3651 node_state,
3652 &CssPropertyType::CaptionSide,
3653 )
3654 .and_then(|p| p.as_caption_side())
3655 }
3656 pub fn get_empty_cells<'a>(
3657 &'a self,
3658 node_data: &'a NodeData,
3659 node_id: &NodeId,
3660 node_state: &StyledNodeState,
3661 ) -> Option<&'a StyleEmptyCellsValue> {
3662 self.get_property(node_data, node_id, node_state, &CssPropertyType::EmptyCells)
3663 .and_then(|p| p.as_empty_cells())
3664 }
3665
3666 pub fn calc_width(
3668 &self,
3669 node_data: &NodeData,
3670 node_id: &NodeId,
3671 styled_node_state: &StyledNodeState,
3672 reference_width: f32,
3673 ) -> f32 {
3674 self.get_width(node_data, node_id, styled_node_state)
3675 .and_then(|w| match w.get_property()? {
3676 LayoutWidth::Px(px) => Some(px.to_pixels_internal(
3677 reference_width,
3678 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3679 )),
3680 _ => Some(0.0), })
3682 .unwrap_or(0.0)
3683 }
3684
3685 pub fn calc_min_width(
3686 &self,
3687 node_data: &NodeData,
3688 node_id: &NodeId,
3689 styled_node_state: &StyledNodeState,
3690 reference_width: f32,
3691 ) -> f32 {
3692 self.get_min_width(node_data, node_id, styled_node_state)
3693 .and_then(|w| {
3694 Some(w.get_property()?.inner.to_pixels_internal(
3695 reference_width,
3696 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3697 ))
3698 })
3699 .unwrap_or(0.0)
3700 }
3701
3702 pub fn calc_max_width(
3703 &self,
3704 node_data: &NodeData,
3705 node_id: &NodeId,
3706 styled_node_state: &StyledNodeState,
3707 reference_width: f32,
3708 ) -> Option<f32> {
3709 self.get_max_width(node_data, node_id, styled_node_state)
3710 .and_then(|w| {
3711 Some(w.get_property()?.inner.to_pixels_internal(
3712 reference_width,
3713 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3714 ))
3715 })
3716 }
3717
3718 pub fn calc_height(
3720 &self,
3721 node_data: &NodeData,
3722 node_id: &NodeId,
3723 styled_node_state: &StyledNodeState,
3724 reference_height: f32,
3725 ) -> f32 {
3726 self.get_height(node_data, node_id, styled_node_state)
3727 .and_then(|h| match h.get_property()? {
3728 LayoutHeight::Px(px) => Some(px.to_pixels_internal(
3729 reference_height,
3730 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3731 )),
3732 _ => Some(0.0), })
3734 .unwrap_or(0.0)
3735 }
3736
3737 pub fn calc_min_height(
3738 &self,
3739 node_data: &NodeData,
3740 node_id: &NodeId,
3741 styled_node_state: &StyledNodeState,
3742 reference_height: f32,
3743 ) -> f32 {
3744 self.get_min_height(node_data, node_id, styled_node_state)
3745 .and_then(|h| {
3746 Some(h.get_property()?.inner.to_pixels_internal(
3747 reference_height,
3748 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3749 ))
3750 })
3751 .unwrap_or(0.0)
3752 }
3753
3754 pub fn calc_max_height(
3755 &self,
3756 node_data: &NodeData,
3757 node_id: &NodeId,
3758 styled_node_state: &StyledNodeState,
3759 reference_height: f32,
3760 ) -> Option<f32> {
3761 self.get_max_height(node_data, node_id, styled_node_state)
3762 .and_then(|h| {
3763 Some(h.get_property()?.inner.to_pixels_internal(
3764 reference_height,
3765 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3766 ))
3767 })
3768 }
3769
3770 pub fn calc_left(
3772 &self,
3773 node_data: &NodeData,
3774 node_id: &NodeId,
3775 styled_node_state: &StyledNodeState,
3776 reference_width: f32,
3777 ) -> Option<f32> {
3778 self.get_left(node_data, node_id, styled_node_state)
3779 .and_then(|l| {
3780 Some(l.get_property()?.inner.to_pixels_internal(
3781 reference_width,
3782 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3783 ))
3784 })
3785 }
3786
3787 pub fn calc_right(
3788 &self,
3789 node_data: &NodeData,
3790 node_id: &NodeId,
3791 styled_node_state: &StyledNodeState,
3792 reference_width: f32,
3793 ) -> Option<f32> {
3794 self.get_right(node_data, node_id, styled_node_state)
3795 .and_then(|r| {
3796 Some(r.get_property()?.inner.to_pixels_internal(
3797 reference_width,
3798 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3799 ))
3800 })
3801 }
3802
3803 pub fn calc_top(
3804 &self,
3805 node_data: &NodeData,
3806 node_id: &NodeId,
3807 styled_node_state: &StyledNodeState,
3808 reference_height: f32,
3809 ) -> Option<f32> {
3810 self.get_top(node_data, node_id, styled_node_state)
3811 .and_then(|t| {
3812 Some(t.get_property()?.inner.to_pixels_internal(
3813 reference_height,
3814 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3815 ))
3816 })
3817 }
3818
3819 pub fn calc_bottom(
3820 &self,
3821 node_data: &NodeData,
3822 node_id: &NodeId,
3823 styled_node_state: &StyledNodeState,
3824 reference_height: f32,
3825 ) -> Option<f32> {
3826 self.get_bottom(node_data, node_id, styled_node_state)
3827 .and_then(|b| {
3828 Some(b.get_property()?.inner.to_pixels_internal(
3829 reference_height,
3830 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3831 ))
3832 })
3833 }
3834
3835 pub fn calc_border_left_width(
3837 &self,
3838 node_data: &NodeData,
3839 node_id: &NodeId,
3840 styled_node_state: &StyledNodeState,
3841 reference_width: f32,
3842 ) -> f32 {
3843 self.get_border_left_width(node_data, node_id, styled_node_state)
3844 .and_then(|b| {
3845 Some(b.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_border_right_width(
3854 &self,
3855 node_data: &NodeData,
3856 node_id: &NodeId,
3857 styled_node_state: &StyledNodeState,
3858 reference_width: f32,
3859 ) -> f32 {
3860 self.get_border_right_width(node_data, node_id, styled_node_state)
3861 .and_then(|b| {
3862 Some(b.get_property()?.inner.to_pixels_internal(
3863 reference_width,
3864 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3865 ))
3866 })
3867 .unwrap_or(0.0)
3868 }
3869
3870 pub fn calc_border_top_width(
3871 &self,
3872 node_data: &NodeData,
3873 node_id: &NodeId,
3874 styled_node_state: &StyledNodeState,
3875 reference_height: f32,
3876 ) -> f32 {
3877 self.get_border_top_width(node_data, node_id, styled_node_state)
3878 .and_then(|b| {
3879 Some(b.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_border_bottom_width(
3888 &self,
3889 node_data: &NodeData,
3890 node_id: &NodeId,
3891 styled_node_state: &StyledNodeState,
3892 reference_height: f32,
3893 ) -> f32 {
3894 self.get_border_bottom_width(node_data, node_id, styled_node_state)
3895 .and_then(|b| {
3896 Some(b.get_property()?.inner.to_pixels_internal(
3897 reference_height,
3898 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3899 ))
3900 })
3901 .unwrap_or(0.0)
3902 }
3903
3904 pub fn calc_padding_left(
3906 &self,
3907 node_data: &NodeData,
3908 node_id: &NodeId,
3909 styled_node_state: &StyledNodeState,
3910 reference_width: f32,
3911 ) -> f32 {
3912 self.get_padding_left(node_data, node_id, styled_node_state)
3913 .and_then(|p| {
3914 Some(p.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_padding_right(
3923 &self,
3924 node_data: &NodeData,
3925 node_id: &NodeId,
3926 styled_node_state: &StyledNodeState,
3927 reference_width: f32,
3928 ) -> f32 {
3929 self.get_padding_right(node_data, node_id, styled_node_state)
3930 .and_then(|p| {
3931 Some(p.get_property()?.inner.to_pixels_internal(
3932 reference_width,
3933 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3934 ))
3935 })
3936 .unwrap_or(0.0)
3937 }
3938
3939 pub fn calc_padding_top(
3940 &self,
3941 node_data: &NodeData,
3942 node_id: &NodeId,
3943 styled_node_state: &StyledNodeState,
3944 reference_height: f32,
3945 ) -> f32 {
3946 self.get_padding_top(node_data, node_id, styled_node_state)
3947 .and_then(|p| {
3948 Some(p.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 pub fn calc_padding_bottom(
3957 &self,
3958 node_data: &NodeData,
3959 node_id: &NodeId,
3960 styled_node_state: &StyledNodeState,
3961 reference_height: f32,
3962 ) -> f32 {
3963 self.get_padding_bottom(node_data, node_id, styled_node_state)
3964 .and_then(|p| {
3965 Some(p.get_property()?.inner.to_pixels_internal(
3966 reference_height,
3967 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3968 ))
3969 })
3970 .unwrap_or(0.0)
3971 }
3972
3973 pub fn calc_margin_left(
3975 &self,
3976 node_data: &NodeData,
3977 node_id: &NodeId,
3978 styled_node_state: &StyledNodeState,
3979 reference_width: f32,
3980 ) -> f32 {
3981 self.get_margin_left(node_data, node_id, styled_node_state)
3982 .and_then(|m| {
3983 Some(m.get_property()?.inner.to_pixels_internal(
3984 reference_width,
3985 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
3986 ))
3987 })
3988 .unwrap_or(0.0)
3989 }
3990
3991 pub fn calc_margin_right(
3992 &self,
3993 node_data: &NodeData,
3994 node_id: &NodeId,
3995 styled_node_state: &StyledNodeState,
3996 reference_width: f32,
3997 ) -> f32 {
3998 self.get_margin_right(node_data, node_id, styled_node_state)
3999 .and_then(|m| {
4000 Some(m.get_property()?.inner.to_pixels_internal(
4001 reference_width,
4002 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4003 ))
4004 })
4005 .unwrap_or(0.0)
4006 }
4007
4008 pub fn calc_margin_top(
4009 &self,
4010 node_data: &NodeData,
4011 node_id: &NodeId,
4012 styled_node_state: &StyledNodeState,
4013 reference_height: f32,
4014 ) -> f32 {
4015 self.get_margin_top(node_data, node_id, styled_node_state)
4016 .and_then(|m| {
4017 Some(m.get_property()?.inner.to_pixels_internal(
4018 reference_height,
4019 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4020 ))
4021 })
4022 .unwrap_or(0.0)
4023 }
4024
4025 pub fn calc_margin_bottom(
4026 &self,
4027 node_data: &NodeData,
4028 node_id: &NodeId,
4029 styled_node_state: &StyledNodeState,
4030 reference_height: f32,
4031 ) -> f32 {
4032 self.get_margin_bottom(node_data, node_id, styled_node_state)
4033 .and_then(|m| {
4034 Some(m.get_property()?.inner.to_pixels_internal(
4035 reference_height,
4036 azul_css::props::basic::pixel::DEFAULT_FONT_SIZE,
4037 ))
4038 })
4039 .unwrap_or(0.0)
4040 }
4041
4042 fn resolve_cascade_keyword(
4080 property: &CssProperty,
4081 property_type: CssPropertyType,
4082 _node_type: &crate::dom::NodeType,
4083 parent_value: Option<&CssProperty>,
4084 ua_value: Option<&'static CssProperty>,
4085 ) -> Option<CssProperty> {
4086 if property_type.is_inheritable() {
4089 return parent_value.cloned().or_else(|| ua_value.cloned());
4090 } else {
4091 return ua_value.cloned();
4092 }
4093 }
4094
4095 fn resolve_property_dependency(
4096 target_property: &CssProperty,
4097 reference_property: &CssProperty,
4098 ) -> Option<CssProperty> {
4099 use azul_css::{
4100 css::CssPropertyValue,
4101 props::{
4102 basic::{font::StyleFontSize, length::SizeMetric, pixel::PixelValue},
4103 layout::*,
4104 style::{SelectionRadius, StyleLetterSpacing, StyleWordSpacing},
4105 },
4106 };
4107
4108 let get_pixel_value = |prop: &CssProperty| -> Option<PixelValue> {
4110 match prop {
4111 CssProperty::FontSize(val) => val.get_property().map(|v| v.inner),
4112 CssProperty::LetterSpacing(val) => val.get_property().map(|v| v.inner),
4113 CssProperty::WordSpacing(val) => val.get_property().map(|v| v.inner),
4114 CssProperty::PaddingLeft(val) => val.get_property().map(|v| v.inner),
4115 CssProperty::PaddingRight(val) => val.get_property().map(|v| v.inner),
4116 CssProperty::PaddingTop(val) => val.get_property().map(|v| v.inner),
4117 CssProperty::PaddingBottom(val) => val.get_property().map(|v| v.inner),
4118 CssProperty::MarginLeft(val) => val.get_property().map(|v| v.inner),
4119 CssProperty::MarginRight(val) => val.get_property().map(|v| v.inner),
4120 CssProperty::MarginTop(val) => val.get_property().map(|v| v.inner),
4121 CssProperty::MarginBottom(val) => val.get_property().map(|v| v.inner),
4122 CssProperty::MinWidth(val) => val.get_property().map(|v| v.inner),
4123 CssProperty::MinHeight(val) => val.get_property().map(|v| v.inner),
4124 CssProperty::MaxWidth(val) => val.get_property().map(|v| v.inner),
4125 CssProperty::MaxHeight(val) => val.get_property().map(|v| v.inner),
4126 CssProperty::SelectionRadius(val) => val.get_property().map(|v| v.inner),
4127 _ => None,
4128 }
4129 };
4130
4131 let target_pixel_value = get_pixel_value(target_property)?;
4132 let reference_pixel_value = get_pixel_value(reference_property)?;
4133
4134 let reference_px = match reference_pixel_value.metric {
4136 SizeMetric::Px => reference_pixel_value.number.get(),
4137 SizeMetric::Pt => reference_pixel_value.number.get() * 1.333333,
4138 SizeMetric::In => reference_pixel_value.number.get() * 96.0,
4139 SizeMetric::Cm => reference_pixel_value.number.get() * 37.7952755906,
4140 SizeMetric::Mm => reference_pixel_value.number.get() * 3.7795275591,
4141 SizeMetric::Em => return None, SizeMetric::Rem => return None, SizeMetric::Percent => return None, SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => return None,
4146 };
4147
4148 let resolved_px = match target_pixel_value.metric {
4150 SizeMetric::Px => target_pixel_value.number.get(),
4151 SizeMetric::Pt => target_pixel_value.number.get() * 1.333333,
4152 SizeMetric::In => target_pixel_value.number.get() * 96.0,
4153 SizeMetric::Cm => target_pixel_value.number.get() * 37.7952755906,
4154 SizeMetric::Mm => target_pixel_value.number.get() * 3.7795275591,
4155 SizeMetric::Em => target_pixel_value.number.get() * reference_px,
4156 SizeMetric::Rem => target_pixel_value.number.get() * reference_px,
4158 SizeMetric::Percent => target_pixel_value.number.get() / 100.0 * reference_px,
4159 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => return None,
4161 };
4162
4163 let resolved_pixel_value = PixelValue::px(resolved_px);
4165
4166 match target_property {
4167 CssProperty::FontSize(_) => Some(CssProperty::FontSize(CssPropertyValue::Exact(
4168 StyleFontSize {
4169 inner: resolved_pixel_value,
4170 },
4171 ))),
4172 CssProperty::LetterSpacing(_) => Some(CssProperty::LetterSpacing(
4173 CssPropertyValue::Exact(StyleLetterSpacing {
4174 inner: resolved_pixel_value,
4175 }),
4176 )),
4177 CssProperty::WordSpacing(_) => Some(CssProperty::WordSpacing(CssPropertyValue::Exact(
4178 StyleWordSpacing {
4179 inner: resolved_pixel_value,
4180 },
4181 ))),
4182 CssProperty::PaddingLeft(_) => Some(CssProperty::PaddingLeft(CssPropertyValue::Exact(
4183 LayoutPaddingLeft {
4184 inner: resolved_pixel_value,
4185 },
4186 ))),
4187 CssProperty::PaddingRight(_) => Some(CssProperty::PaddingRight(
4188 CssPropertyValue::Exact(LayoutPaddingRight {
4189 inner: resolved_pixel_value,
4190 }),
4191 )),
4192 CssProperty::PaddingTop(_) => Some(CssProperty::PaddingTop(CssPropertyValue::Exact(
4193 LayoutPaddingTop {
4194 inner: resolved_pixel_value,
4195 },
4196 ))),
4197 CssProperty::PaddingBottom(_) => Some(CssProperty::PaddingBottom(
4198 CssPropertyValue::Exact(LayoutPaddingBottom {
4199 inner: resolved_pixel_value,
4200 }),
4201 )),
4202 CssProperty::MarginLeft(_) => Some(CssProperty::MarginLeft(CssPropertyValue::Exact(
4203 LayoutMarginLeft {
4204 inner: resolved_pixel_value,
4205 },
4206 ))),
4207 CssProperty::MarginRight(_) => Some(CssProperty::MarginRight(CssPropertyValue::Exact(
4208 LayoutMarginRight {
4209 inner: resolved_pixel_value,
4210 },
4211 ))),
4212 CssProperty::MarginTop(_) => Some(CssProperty::MarginTop(CssPropertyValue::Exact(
4213 LayoutMarginTop {
4214 inner: resolved_pixel_value,
4215 },
4216 ))),
4217 CssProperty::MarginBottom(_) => Some(CssProperty::MarginBottom(
4218 CssPropertyValue::Exact(LayoutMarginBottom {
4219 inner: resolved_pixel_value,
4220 }),
4221 )),
4222 CssProperty::MinWidth(_) => Some(CssProperty::MinWidth(CssPropertyValue::Exact(
4223 LayoutMinWidth {
4224 inner: resolved_pixel_value,
4225 },
4226 ))),
4227 CssProperty::MinHeight(_) => Some(CssProperty::MinHeight(CssPropertyValue::Exact(
4228 LayoutMinHeight {
4229 inner: resolved_pixel_value,
4230 },
4231 ))),
4232 CssProperty::MaxWidth(_) => Some(CssProperty::MaxWidth(CssPropertyValue::Exact(
4233 LayoutMaxWidth {
4234 inner: resolved_pixel_value,
4235 },
4236 ))),
4237 CssProperty::MaxHeight(_) => Some(CssProperty::MaxHeight(CssPropertyValue::Exact(
4238 LayoutMaxHeight {
4239 inner: resolved_pixel_value,
4240 },
4241 ))),
4242 CssProperty::SelectionRadius(_) => Some(CssProperty::SelectionRadius(
4243 CssPropertyValue::Exact(SelectionRadius {
4244 inner: resolved_pixel_value,
4245 }),
4246 )),
4247 _ => None,
4248 }
4249 }
4250
4251 fn build_dependency_chain(
4269 &self,
4270 node_id: NodeId,
4271 parent_id: Option<NodeId>,
4272 property: &CssProperty,
4273 ) -> Option<CssDependencyChain> {
4274 use azul_css::props::basic::{length::SizeMetric, pixel::PixelValue};
4275
4276 let prop_type = property.get_type();
4277
4278 if prop_type != CssPropertyType::FontSize {
4281 return None;
4282 }
4283
4284 let pixel_value = match property {
4286 CssProperty::FontSize(val) => val.get_property().map(|v| &v.inner)?,
4287 _ => return None,
4288 };
4289
4290 let number = pixel_value.number.get();
4291
4292 let source_node = parent_id?;
4294
4295 match pixel_value.metric {
4296 SizeMetric::Px => Some(CssDependencyChain::absolute(prop_type, number)),
4297 SizeMetric::Pt => {
4298 Some(CssDependencyChain::absolute(prop_type, number * 1.333333))
4300 }
4301 SizeMetric::Em => Some(CssDependencyChain::em(prop_type, source_node, number)),
4302 SizeMetric::Rem => {
4303 Some(CssDependencyChain::rem(prop_type, number))
4305 }
4306 SizeMetric::Percent => Some(CssDependencyChain::percent(
4307 prop_type,
4308 source_node,
4309 number / 100.0,
4310 )),
4311 SizeMetric::In => {
4312 Some(CssDependencyChain::absolute(prop_type, number * 96.0))
4314 }
4315 SizeMetric::Cm => {
4316 Some(CssDependencyChain::absolute(
4318 prop_type,
4319 number * 37.7952755906,
4320 ))
4321 }
4322 SizeMetric::Mm => {
4323 Some(CssDependencyChain::absolute(
4325 prop_type,
4326 number * 3.7795275591,
4327 ))
4328 }
4329 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => {
4332 None
4334 }
4335 }
4336 }
4337
4338 pub fn apply_ua_css(&mut self, node_data: &[NodeData]) {
4346 use azul_css::props::property::CssPropertyType;
4347
4348 for (node_index, node) in node_data.iter().enumerate() {
4350 let node_id = NodeId::new(node_index);
4351 let node_type = &node.node_type;
4352
4353 let property_types = [
4356 CssPropertyType::Display,
4357 CssPropertyType::Width,
4358 CssPropertyType::Height,
4359 CssPropertyType::FontSize,
4360 CssPropertyType::FontWeight,
4361 CssPropertyType::FontFamily,
4362 CssPropertyType::MarginTop,
4363 CssPropertyType::MarginBottom,
4364 CssPropertyType::MarginLeft,
4365 CssPropertyType::MarginRight,
4366 CssPropertyType::PaddingTop,
4367 CssPropertyType::PaddingBottom,
4368 CssPropertyType::PaddingLeft,
4369 CssPropertyType::PaddingRight,
4370 ];
4372
4373 for prop_type in &property_types {
4374 if let Some(ua_prop) = crate::ua_css::get_ua_property(node_type, *prop_type) {
4376 let has_inline = node.css_props.iter().any(|p| {
4379 let is_normal = p.apply_if.as_slice().is_empty();
4381 is_normal && p.property.get_type() == *prop_type
4382 });
4383
4384 let has_css = self
4385 .css_normal_props
4386 .get(node_id.index())
4387 .map(|map| map.contains_key(prop_type))
4388 .unwrap_or(false);
4389
4390 let has_cascaded = self
4391 .cascaded_normal_props
4392 .get(node_id.index())
4393 .map(|map| map.contains_key(prop_type))
4394 .unwrap_or(false);
4395
4396 if !has_inline && !has_css && !has_cascaded {
4398 self.cascaded_normal_props[node_id.index()]
4399 .entry(*prop_type)
4400 .or_insert_with(|| ua_prop.clone());
4401 }
4402 }
4403 }
4404 }
4405 }
4406
4407 pub fn compute_inherited_values(
4413 &mut self,
4414 node_hierarchy: &[NodeHierarchyItem],
4415 node_data: &[NodeData],
4416 ) -> Vec<NodeId> {
4417 node_hierarchy
4418 .iter()
4419 .enumerate()
4420 .filter_map(|(node_index, hierarchy_item)| {
4421 let node_id = NodeId::new(node_index);
4422 let parent_id = hierarchy_item.parent_id();
4423 let parent_computed =
4424 parent_id.and_then(|pid| self.computed_values.get(pid.index()).cloned());
4425
4426 let mut ctx = InheritanceContext {
4427 node_id,
4428 parent_id,
4429 computed_values: BTreeMap::new(),
4430 dependency_chains: BTreeMap::new(),
4431 };
4432
4433 if let Some(ref parent_values) = parent_computed {
4435 self.inherit_from_parent(&mut ctx, parent_values);
4436 }
4437
4438 self.apply_cascade_properties(
4440 &mut ctx,
4441 node_id,
4442 &parent_computed,
4443 node_data,
4444 node_index,
4445 );
4446
4447 let changed = self.store_if_changed(&ctx);
4449 changed.then_some(node_id)
4450 })
4451 .collect()
4452 }
4453
4454 fn inherit_from_parent(
4456 &self,
4457 ctx: &mut InheritanceContext,
4458 parent_values: &BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4459 ) {
4460 for (prop_type, prop_with_origin) in
4461 parent_values.iter().filter(|(pt, _)| pt.is_inheritable())
4462 {
4463 ctx.computed_values.insert(
4464 *prop_type,
4465 CssPropertyWithOrigin {
4466 property: prop_with_origin.property.clone(),
4467 origin: CssPropertyOrigin::Inherited,
4468 },
4469 );
4470
4471 if *prop_type == CssPropertyType::FontSize {
4473 continue;
4474 }
4475
4476 if let Some(chain) = ctx
4477 .parent_id
4478 .and_then(|pid| self.dependency_chains.get(pid.index()))
4479 .and_then(|chains| chains.get(prop_type))
4480 {
4481 ctx.dependency_chains.insert(*prop_type, chain.clone());
4482 }
4483 }
4484 }
4485
4486 fn apply_cascade_properties(
4488 &self,
4489 ctx: &mut InheritanceContext,
4490 node_id: NodeId,
4491 parent_computed: &Option<BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
4492 node_data: &[NodeData],
4493 node_index: usize,
4494 ) {
4495 if let Some(cascaded_props) = self.cascaded_normal_props.get(node_id.index()).cloned() {
4497 for (prop_type, prop) in cascaded_props.iter() {
4498 if self.should_apply_cascaded(&ctx.computed_values, *prop_type, prop) {
4499 self.process_property(ctx, prop, parent_computed);
4500 }
4501 }
4502 }
4503
4504 if let Some(css_props) = self.css_normal_props.get(node_id.index()) {
4506 for (_, prop) in css_props.iter() {
4507 self.process_property(ctx, prop, parent_computed);
4508 }
4509 }
4510
4511 for inline_prop in node_data[node_index].css_props.iter() {
4513 if inline_prop.apply_if.as_slice().is_empty() {
4515 self.process_property(ctx, &inline_prop.property, parent_computed);
4516 }
4517 }
4518
4519 if let Some(user_props) = self.user_overridden_properties.get(node_id.index()) {
4521 for (_, prop) in user_props.iter() {
4522 self.process_property(ctx, prop, parent_computed);
4523 }
4524 }
4525 }
4526
4527 fn should_apply_cascaded(
4529 &self,
4530 computed: &BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4531 prop_type: CssPropertyType,
4532 prop: &CssProperty,
4533 ) -> bool {
4534 if prop_type == CssPropertyType::FontSize {
4536 if let Some(existing) = computed.get(&prop_type) {
4537 if existing.origin == CssPropertyOrigin::Inherited
4538 && Self::has_relative_font_size_unit(prop)
4539 {
4540 return false;
4541 }
4542 }
4543 }
4544
4545 match computed.get(&prop_type) {
4546 None => true,
4547 Some(existing) => existing.origin == CssPropertyOrigin::Inherited,
4548 }
4549 }
4550
4551 fn process_property(
4553 &self,
4554 ctx: &mut InheritanceContext,
4555 prop: &CssProperty,
4556 parent_computed: &Option<BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
4557 ) {
4558 let prop_type = prop.get_type();
4559
4560 let resolved = if prop_type == CssPropertyType::FontSize {
4561 self.resolve_font_size_property(prop, parent_computed)
4562 } else {
4563 self.resolve_other_property(prop, &ctx.computed_values)
4564 };
4565
4566 ctx.computed_values.insert(
4567 prop_type,
4568 CssPropertyWithOrigin {
4569 property: resolved.clone(),
4570 origin: CssPropertyOrigin::Own,
4571 },
4572 );
4573
4574 if let Some(chain) = self.build_dependency_chain(ctx.node_id, ctx.parent_id, &resolved) {
4575 ctx.dependency_chains.insert(prop_type, chain);
4576 }
4577 }
4578
4579 fn resolve_font_size_property(
4581 &self,
4582 prop: &CssProperty,
4583 parent_computed: &Option<BTreeMap<CssPropertyType, CssPropertyWithOrigin>>,
4584 ) -> CssProperty {
4585 const DEFAULT_FONT_SIZE_PX: f32 = 16.0;
4586
4587 let parent_font_size = parent_computed
4588 .as_ref()
4589 .and_then(|p| p.get(&CssPropertyType::FontSize));
4590
4591 match parent_font_size {
4592 Some(pfs) => Self::resolve_property_dependency(prop, &pfs.property)
4593 .unwrap_or_else(|| Self::resolve_font_size_to_pixels(prop, DEFAULT_FONT_SIZE_PX)),
4594 None => Self::resolve_font_size_to_pixels(prop, DEFAULT_FONT_SIZE_PX),
4595 }
4596 }
4597
4598 fn resolve_other_property(
4600 &self,
4601 prop: &CssProperty,
4602 computed: &BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4603 ) -> CssProperty {
4604 computed
4605 .get(&CssPropertyType::FontSize)
4606 .and_then(|fs| Self::resolve_property_dependency(prop, &fs.property))
4607 .unwrap_or_else(|| prop.clone())
4608 }
4609
4610 fn resolve_font_size_to_pixels(prop: &CssProperty, reference_px: f32) -> CssProperty {
4612 use azul_css::{
4613 css::CssPropertyValue,
4614 props::basic::{font::StyleFontSize, length::SizeMetric, pixel::PixelValue},
4615 };
4616
4617 const DEFAULT_FONT_SIZE_PX: f32 = 16.0;
4618
4619 let CssProperty::FontSize(css_val) = prop else {
4620 return prop.clone();
4621 };
4622
4623 let Some(font_size) = css_val.get_property() else {
4624 return prop.clone();
4625 };
4626
4627 let resolved_px = match font_size.inner.metric {
4628 SizeMetric::Px => font_size.inner.number.get(),
4629 SizeMetric::Pt => font_size.inner.number.get() * 1.333333,
4630 SizeMetric::In => font_size.inner.number.get() * 96.0,
4631 SizeMetric::Cm => font_size.inner.number.get() * 37.7952755906,
4632 SizeMetric::Mm => font_size.inner.number.get() * 3.7795275591,
4633 SizeMetric::Em => font_size.inner.number.get() * reference_px,
4634 SizeMetric::Rem => font_size.inner.number.get() * DEFAULT_FONT_SIZE_PX,
4635 SizeMetric::Percent => font_size.inner.number.get() / 100.0 * reference_px,
4636 SizeMetric::Vw | SizeMetric::Vh | SizeMetric::Vmin | SizeMetric::Vmax => {
4637 return prop.clone();
4638 }
4639 };
4640
4641 CssProperty::FontSize(CssPropertyValue::Exact(StyleFontSize {
4642 inner: PixelValue::px(resolved_px),
4643 }))
4644 }
4645
4646 fn has_relative_font_size_unit(prop: &CssProperty) -> bool {
4648 use azul_css::props::basic::length::SizeMetric;
4649
4650 let CssProperty::FontSize(css_val) = prop else {
4651 return false;
4652 };
4653
4654 css_val
4655 .get_property()
4656 .map(|fs| {
4657 matches!(
4658 fs.inner.metric,
4659 SizeMetric::Em | SizeMetric::Rem | SizeMetric::Percent
4660 )
4661 })
4662 .unwrap_or(false)
4663 }
4664
4665 fn store_if_changed(&mut self, ctx: &InheritanceContext) -> bool {
4667 let values_changed = self
4668 .computed_values
4669 .get(ctx.node_id.index())
4670 .map(|old| old != &ctx.computed_values)
4671 .unwrap_or(true);
4672
4673 let chains_changed = self
4674 .dependency_chains
4675 .get(ctx.node_id.index())
4676 .map(|old| old != &ctx.dependency_chains)
4677 .unwrap_or(!ctx.dependency_chains.is_empty());
4678
4679 let changed = values_changed || chains_changed;
4680
4681 self.computed_values[ctx.node_id.index()] = ctx.computed_values.clone();
4682 if !ctx.dependency_chains.is_empty() {
4683 self.dependency_chains[ctx.node_id.index()] = ctx.dependency_chains.clone();
4684 }
4685
4686 changed
4687 }
4688}
4689
4690struct InheritanceContext {
4692 node_id: NodeId,
4693 parent_id: Option<NodeId>,
4694 computed_values: BTreeMap<CssPropertyType, CssPropertyWithOrigin>,
4695 dependency_chains: BTreeMap<CssPropertyType, CssDependencyChain>,
4696}
4697
4698impl CssPropertyCache {
4699 pub fn resolve_dependency_chain(
4715 &self,
4716 node_id: NodeId,
4717 property_type: CssPropertyType,
4718 root_font_size: f32,
4719 ) -> Option<f32> {
4720 let chain = self.get_chain(node_id, property_type)?;
4721
4722 if let Some(cached) = chain.cached_pixels {
4723 return Some(cached);
4724 }
4725
4726 chain.steps.clone().iter().try_fold(None, |_, step| {
4727 Some(self.resolve_step(step, property_type, root_font_size))
4728 })?
4729 }
4730
4731 fn get_chain(
4733 &self,
4734 node_id: NodeId,
4735 property_type: CssPropertyType,
4736 ) -> Option<&CssDependencyChain> {
4737 self.dependency_chains
4738 .get(node_id.index())
4739 .and_then(|chains| chains.get(&property_type))
4740 }
4741
4742 fn resolve_step(
4744 &self,
4745 step: &CssDependencyChainStep,
4746 property_type: CssPropertyType,
4747 root_font_size: f32,
4748 ) -> Option<f32> {
4749 match step {
4750 CssDependencyChainStep::Absolute { pixels } => Some(*pixels),
4751 CssDependencyChainStep::Percent {
4752 source_node,
4753 factor,
4754 } => {
4755 let source_val = self.get_cached_pixels(*source_node, property_type)?;
4756 Some(source_val * factor)
4757 }
4758 CssDependencyChainStep::Em {
4759 source_node,
4760 factor,
4761 } => {
4762 let font_size = self.get_cached_pixels(*source_node, CssPropertyType::FontSize)?;
4763 Some(font_size * factor)
4764 }
4765 CssDependencyChainStep::Rem { factor } => Some(root_font_size * factor),
4766 }
4767 }
4768
4769 fn get_cached_pixels(&self, node_id: NodeId, property_type: CssPropertyType) -> Option<f32> {
4771 self.get_chain(node_id, property_type)
4772 .and_then(|chain| chain.cached_pixels)
4773 }
4774
4775 pub fn update_property_and_invalidate_dependents(
4793 &mut self,
4794 node_id: NodeId,
4795 property: CssProperty,
4796 node_hierarchy: &[NodeHierarchyItem],
4797 _node_data: &[NodeData],
4798 ) -> Vec<NodeId> {
4799 let prop_type = property.get_type();
4800
4801 self.update_computed_property(node_id, property.clone());
4802 self.rebuild_dependency_chain(node_id, prop_type, &property, node_hierarchy);
4803
4804 let mut affected = self.invalidate_dependents(node_id);
4805 affected.push(node_id);
4806 affected
4807 }
4808
4809 fn update_computed_property(&mut self, node_id: NodeId, property: CssProperty) {
4811 self.computed_values[node_id.index()]
4812 .insert(
4813 property.get_type(),
4814 CssPropertyWithOrigin {
4815 property,
4816 origin: CssPropertyOrigin::Own,
4817 },
4818 );
4819 }
4820
4821 fn rebuild_dependency_chain(
4823 &mut self,
4824 node_id: NodeId,
4825 prop_type: CssPropertyType,
4826 property: &CssProperty,
4827 node_hierarchy: &[NodeHierarchyItem],
4828 ) {
4829 let parent_id = node_hierarchy
4830 .get(node_id.index())
4831 .and_then(|h| h.parent_id());
4832
4833 if let Some(chain) = self.build_dependency_chain(node_id, parent_id, property) {
4834 self.dependency_chains[node_id.index()]
4835 .insert(prop_type, chain);
4836 }
4837 }
4838
4839 fn invalidate_dependents(&mut self, node_id: NodeId) -> Vec<NodeId> {
4841 self.dependency_chains
4842 .iter_mut()
4843 .enumerate()
4844 .filter_map(|(dep_node_idx, chains)| {
4845 let affected = chains.values_mut().any(|chain| {
4846 if chain.depends_on(node_id) {
4847 chain.cached_pixels = None;
4848 true
4849 } else {
4850 false
4851 }
4852 });
4853 affected.then_some(NodeId::new(dep_node_idx))
4854 })
4855 .collect()
4856 }
4857
4858 const UA_PROPERTY_TYPES: &'static [CssPropertyType] = &[
4861 CssPropertyType::Display,
4862 CssPropertyType::Width,
4863 CssPropertyType::Height,
4864 CssPropertyType::FontSize,
4865 CssPropertyType::FontWeight,
4866 CssPropertyType::FontFamily,
4867 CssPropertyType::MarginTop,
4868 CssPropertyType::MarginBottom,
4869 CssPropertyType::MarginLeft,
4870 CssPropertyType::MarginRight,
4871 CssPropertyType::PaddingTop,
4872 CssPropertyType::PaddingBottom,
4873 CssPropertyType::PaddingLeft,
4874 CssPropertyType::PaddingRight,
4875 CssPropertyType::BreakInside,
4876 CssPropertyType::BreakBefore,
4877 CssPropertyType::BreakAfter,
4878 CssPropertyType::BorderCollapse,
4879 CssPropertyType::BorderSpacing,
4880 CssPropertyType::TextAlign,
4881 CssPropertyType::VerticalAlign,
4882 CssPropertyType::ListStyleType,
4883 CssPropertyType::ListStylePosition,
4884 ];
4885
4886 pub fn build_resolved_cache(
4899 &self,
4900 node_data: &[NodeData],
4901 styled_nodes: &[crate::styled_dom::StyledNode],
4902 ) -> Vec<Vec<(CssPropertyType, CssProperty)>> {
4903 use alloc::collections::BTreeSet;
4904 use azul_css::dynamic_selector::{DynamicSelector, PseudoStateType};
4905
4906 let node_count = node_data.len();
4907 let mut resolved = Vec::with_capacity(node_count);
4908
4909 for node_index in 0..node_count {
4910 let node_id = NodeId::new(node_index);
4911 let nd = &node_data[node_index];
4912 let node_state = &styled_nodes[node_index].styled_node_state;
4913
4914 let mut prop_types = BTreeSet::new();
4917
4918 if let Some(map) = self.user_overridden_properties.get(node_id.index()) {
4919 prop_types.extend(map.keys().copied());
4920 }
4921 for css_prop in nd.css_props.iter() {
4922 let conditions = css_prop.apply_if.as_slice();
4923 let matches = if conditions.is_empty() {
4924 true
4925 } else {
4926 conditions.iter().all(|c| match c {
4927 DynamicSelector::PseudoState(PseudoStateType::Hover) => node_state.hover,
4928 DynamicSelector::PseudoState(PseudoStateType::Active) => node_state.active,
4929 DynamicSelector::PseudoState(PseudoStateType::Focus) => node_state.focused,
4930 DynamicSelector::PseudoState(PseudoStateType::Dragging) => node_state.dragging,
4931 DynamicSelector::PseudoState(PseudoStateType::DragOver) => node_state.drag_over,
4932 _ => false,
4933 })
4934 };
4935 if matches {
4936 prop_types.insert(css_prop.property.get_type());
4937 }
4938 }
4939 if let Some(map) = self.css_normal_props.get(node_id.index()) {
4940 prop_types.extend(map.keys().copied());
4941 }
4942 if let Some(map) = self.cascaded_normal_props.get(node_id.index()) {
4943 prop_types.extend(map.keys().copied());
4944 }
4945 if let Some(map) = self.computed_values.get(node_id.index()) {
4946 for pt in map.keys() {
4947 if pt.is_inheritable() {
4948 prop_types.insert(*pt);
4949 }
4950 }
4951 }
4952 if node_state.hover {
4954 if let Some(map) = self.css_hover_props.get(node_id.index()) {
4955 prop_types.extend(map.keys().copied());
4956 }
4957 if let Some(map) = self.cascaded_hover_props.get(node_id.index()) {
4958 prop_types.extend(map.keys().copied());
4959 }
4960 }
4961 if node_state.active {
4962 if let Some(map) = self.css_active_props.get(node_id.index()) {
4963 prop_types.extend(map.keys().copied());
4964 }
4965 if let Some(map) = self.cascaded_active_props.get(node_id.index()) {
4966 prop_types.extend(map.keys().copied());
4967 }
4968 }
4969 if node_state.focused {
4970 if let Some(map) = self.css_focus_props.get(node_id.index()) {
4971 prop_types.extend(map.keys().copied());
4972 }
4973 if let Some(map) = self.cascaded_focus_props.get(node_id.index()) {
4974 prop_types.extend(map.keys().copied());
4975 }
4976 }
4977 if node_state.dragging {
4978 if let Some(map) = self.css_dragging_props.get(node_id.index()) {
4979 prop_types.extend(map.keys().copied());
4980 }
4981 if let Some(map) = self.cascaded_dragging_props.get(node_id.index()) {
4982 prop_types.extend(map.keys().copied());
4983 }
4984 }
4985 if node_state.drag_over {
4986 if let Some(map) = self.css_drag_over_props.get(node_id.index()) {
4987 prop_types.extend(map.keys().copied());
4988 }
4989 if let Some(map) = self.cascaded_drag_over_props.get(node_id.index()) {
4990 prop_types.extend(map.keys().copied());
4991 }
4992 }
4993 for pt in Self::UA_PROPERTY_TYPES {
4995 if crate::ua_css::get_ua_property(&nd.node_type, *pt).is_some() {
4996 prop_types.insert(*pt);
4997 }
4998 }
4999
5000 let mut props: Vec<(CssPropertyType, CssProperty)> =
5003 Vec::with_capacity(prop_types.len());
5004 for prop_type in &prop_types {
5005 if let Some(prop) = self.get_property_slow(nd, &node_id, node_state, prop_type) {
5006 props.push((*prop_type, prop.clone()));
5007 }
5008 }
5009 resolved.push(props);
5011 }
5012
5013 resolved
5014 }
5015
5016 pub fn invalidate_resolved_node(
5022 &mut self,
5023 node_id: NodeId,
5024 node_data: &NodeData,
5025 styled_node: &crate::styled_dom::StyledNode,
5026 ) {
5027 let idx = node_id.index();
5028 if idx >= self.resolved_cache.len() {
5029 return;
5030 }
5031
5032 let node_state = &styled_node.styled_node_state;
5033
5034 let mut prop_types = alloc::collections::BTreeSet::new();
5036
5037 if let Some(map) = self.user_overridden_properties.get(node_id.index()) {
5038 prop_types.extend(map.keys().copied());
5039 }
5040 for css_prop in node_data.css_props.iter() {
5041 prop_types.insert(css_prop.property.get_type());
5042 }
5043 if let Some(map) = self.css_normal_props.get(node_id.index()) {
5044 prop_types.extend(map.keys().copied());
5045 }
5046 if let Some(map) = self.cascaded_normal_props.get(node_id.index()) {
5047 prop_types.extend(map.keys().copied());
5048 }
5049 if let Some(map) = self.computed_values.get(node_id.index()) {
5050 prop_types.extend(map.keys().copied());
5051 }
5052 for pt in Self::UA_PROPERTY_TYPES {
5053 if crate::ua_css::get_ua_property(&node_data.node_type, *pt).is_some() {
5054 prop_types.insert(*pt);
5055 }
5056 }
5057 if node_state.hover {
5058 if let Some(map) = self.css_hover_props.get(node_id.index()) {
5059 prop_types.extend(map.keys().copied());
5060 }
5061 if let Some(map) = self.cascaded_hover_props.get(node_id.index()) {
5062 prop_types.extend(map.keys().copied());
5063 }
5064 }
5065 if node_state.active {
5066 if let Some(map) = self.css_active_props.get(node_id.index()) {
5067 prop_types.extend(map.keys().copied());
5068 }
5069 if let Some(map) = self.cascaded_active_props.get(node_id.index()) {
5070 prop_types.extend(map.keys().copied());
5071 }
5072 }
5073 if node_state.focused {
5074 if let Some(map) = self.css_focus_props.get(node_id.index()) {
5075 prop_types.extend(map.keys().copied());
5076 }
5077 if let Some(map) = self.cascaded_focus_props.get(node_id.index()) {
5078 prop_types.extend(map.keys().copied());
5079 }
5080 }
5081
5082 let mut props = Vec::with_capacity(prop_types.len());
5083 for prop_type in &prop_types {
5084 if let Some(prop) = self.get_property_slow(node_data, &node_id, node_state, prop_type) {
5085 props.push((*prop_type, prop.clone()));
5086 }
5087 }
5088
5089 self.resolved_cache[idx] = props;
5091 }
5092
5093 pub fn invalidate_resolved_cache(&mut self) {
5095 self.resolved_cache.clear();
5096 }
5097}
5098
5099#[cfg(test)]
5100mod tests {
5101 use super::*;
5102 use crate::dom::NodeType;
5103
5104 #[test]
5105 fn test_ua_css_p_tag_properties() {
5106 let cache = CssPropertyCache::empty(1);
5108
5109 let mut node_data = NodeData::create_node(NodeType::P);
5111
5112 let node_id = NodeId::new(0);
5113 let node_state = StyledNodeState::default();
5114
5115 let display = cache.get_display(&node_data, &node_id, &node_state);
5117 assert!(
5118 display.is_some(),
5119 "Expected <p> to have display property from UA CSS"
5120 );
5121 if let Some(d) = display {
5122 if let Some(display_value) = d.get_property() {
5123 assert_eq!(
5124 *display_value,
5125 LayoutDisplay::Block,
5126 "Expected <p> to have display: block, got {:?}",
5127 display_value
5128 );
5129 }
5130 }
5131
5132 let width = cache.get_width(&node_data, &node_id, &node_state);
5136 assert!(
5138 width.is_none(),
5139 "Expected <p> to NOT have explicit width (should be auto), but got {:?}",
5140 width
5141 );
5142
5143 let height = cache.get_height(&node_data, &node_id, &node_state);
5146 println!("Height for <p> tag: {:?}", height);
5147
5148 assert!(
5150 height.is_none(),
5151 "Expected <p> to NOT have explicit height (should be auto), but got {:?}",
5152 height
5153 );
5154 }
5155
5156 #[test]
5157 fn test_ua_css_body_tag_properties() {
5158 let cache = CssPropertyCache::empty(1);
5159
5160 let node_data = NodeData::create_node(NodeType::Body);
5161
5162 let node_id = NodeId::new(0);
5163 let node_state = StyledNodeState::default();
5164
5165 let width = cache.get_width(&node_data, &node_id, &node_state);
5168 assert!(
5170 width.is_none(),
5171 "Expected <body> to NOT have explicit width (should be auto), but got {:?}",
5172 width
5173 );
5174
5175 let height = cache.get_height(&node_data, &node_id, &node_state);
5178 assert!(
5179 height.is_none(),
5180 "<body> should not have explicit height from UA CSS (should be auto)"
5181 );
5182
5183 let margin_top = cache.get_margin_top(&node_data, &node_id, &node_state);
5185 assert!(
5186 margin_top.is_some(),
5187 "Expected <body> to have margin-top from UA CSS"
5188 );
5189 }
5190}