accessibility_rs/engine/styles/
layout.rs1use accessibility_scraper::ElementRef;
2use accessibility_scraper::Html;
3use accessibility_tree::style::values::LengthOrPercentageOrAuto;
4use accessibility_tree::style::ComputedValues;
5use accessibility_tree::style::StyleSet;
6use ego_tree::NodeRef;
7use std::collections::HashSet;
8use std::sync::Arc;
9use taffy::prelude::*;
10use taffy::style::Dimension;
11
12lazy_static! {
13 static ref NODE_IGNORE: HashSet<&'static str> =
14 HashSet::from(["meta", "style", "link", "script", "head", "html", "body"]);
15}
16
17pub fn length_dimensions(v: &LengthOrPercentageOrAuto) -> Dimension {
19 match v {
20 LengthOrPercentageOrAuto::Length(l) => Dimension::Length(l.px),
21 LengthOrPercentageOrAuto::Percentage(l) => Dimension::Percent(l.unit_value),
22 LengthOrPercentageOrAuto::Auto => Dimension::Auto,
23 }
24}
25
26pub fn node_layout_style(style: Arc<ComputedValues>, element: &ElementRef) -> Style {
28 let physical_size = style.box_size().size_to_physical(style.writing_mode());
29 let mut size = Size {
30 width: length_dimensions(&physical_size.x),
31 height: length_dimensions(&physical_size.y),
32 };
33
34 if element.value().name() == "img" {
36 let width = element.attr("width");
37 let height = element.attr("height");
38 if physical_size.x.inner_px() == 0.0 {
39 match width {
40 Some(w) => {
41 let w = w.parse::<f32>();
42 match w {
43 Ok(w) => {
44 size.width = length(w);
45 }
46 _ => (),
47 }
48 }
49 _ => (),
50 }
51 }
52 if physical_size.y.inner_px() == 0.0 {
53 match height {
54 Some(h) => {
55 let h = h.parse::<f32>();
56
57 match h {
58 Ok(h) => {
59 size.height = length(h);
60 }
61 _ => (),
62 }
63 }
64 _ => (),
65 }
66 }
67 }
68
69 Style {
71 size,
72 border: length(style.border_width().inner_px()),
73 padding: length(style.padding().inner_px()),
74 margin: length(style.margin().inner_px()),
75 ..Default::default()
76 }
77}
78
79pub fn push_leaf<'a, 'b, 'c>(
81 node: &NodeRef<'_, accessibility_scraper::Node>,
82 author: &StyleSet,
83 document: &'a Html,
84 taffy: &mut TaffyTree,
85 l_leafs: &mut Vec<NodeId>,
86) {
87 match ElementRef::wrap(*node) {
88 Some(element) => {
89 let name = element.value().name();
90 if !NODE_IGNORE.contains(name) {
91 let style = accessibility_tree::style::cascade::style_for_element_ref(
92 &element, &author, &document,
93 );
94
95 if node.has_children() {
96 let children = node.children();
97 let mut child_leafs: Vec<NodeId> = vec![];
98
99 for child in children {
101 push_leaf(&child, author, document, taffy, &mut child_leafs);
102 }
103
104 l_leafs.push(
105 taffy
106 .new_with_children(node_layout_style(style, &element), &child_leafs)
107 .unwrap(),
108 );
109 } else {
110 l_leafs.push(taffy.new_leaf(node_layout_style(style, &element)).unwrap());
111 }
112 }
113 }
114 _ => (),
115 }
116}
117
118pub fn leaf<'a, 'b, 'c>(
120 element: &ElementRef,
121 author: &StyleSet,
122 document: &'a Html,
123 taffy: &mut TaffyTree,
124) -> NodeId {
125 let mut l_leafs: Vec<NodeId> = vec![];
126 let mut children = element.children();
127
128 while let Some(child) = children.next() {
129 push_leaf(&child, author, document, taffy, &mut l_leafs);
130 }
131
132 let style =
133 accessibility_tree::style::cascade::style_for_element_ref(&element, &author, &document);
134
135 let leaf_style = node_layout_style(style, &element);
136
137 if l_leafs.len() > 0 {
139 taffy.new_with_children(leaf_style, &l_leafs)
140 } else {
141 taffy.new_leaf(leaf_style)
142 }
143 .unwrap()
144}