Skip to content

Commit

Permalink
chore(innate): add layout nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mendez committed Oct 7, 2023
1 parent 7d9c75b commit 62b7a91
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 44 deletions.
1 change: 1 addition & 0 deletions kayle_innate/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions kayle_innate/kayle_innate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ ego-tree = { workspace = true }
victor_tree = { version = "0.0.7", path = "../kayle_victor/victor" }
markup5ever = "0.11.0"
cssparser = { workspace = true }
slotmap = "1.0.6"

[dev-dependencies]
wasm-bindgen-test = "0.3.37"
Expand Down
21 changes: 13 additions & 8 deletions kayle_innate/kayle_innate/src/engine/audit/auditor.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
use super::tree::parse_accessibility_tree;
use crate::{console_log, now};
use markup5ever::local_name;
use scraper_forky::ElementRef;
use scraper_forky::Html;
use slotmap::DefaultKey;
use taffy::Taffy;
use victor_tree::style::StyleSet;
use markup5ever::local_name;

use super::tree::parse_accessibility_tree;

/// the intro to an audit
pub struct Auditor<'a> {
/// the html document
pub document: &'a Html,
/// the tree to map to nodes
pub tree: std::collections::BTreeMap<&'a str, Vec<ElementRef<'a>>>,
pub tree: std::collections::BTreeMap<&'a str, Vec<(ElementRef<'a>, DefaultKey)>>,
/// styles for the audit
pub author: StyleSet,
// /// the matching context for css selectors
/// the matching context for css selectors
pub match_context: selectors::matching::MatchingContext<'a, scraper_forky::selector::Simple>,
/// layout handling
pub taffy: Taffy,
}

impl<'a> Auditor<'a> {
Expand All @@ -25,7 +28,7 @@ impl<'a> Auditor<'a> {
match_context: selectors::matching::MatchingContext<'a, scraper_forky::selector::Simple>,
) -> Auditor<'a> {
let tt = now();

// TODO: make stylesheet building optional and only on first requirement
let author = {
let mut author = victor_tree::style::StyleSetBuilder::new();
if !css_rules.is_empty() {
Expand All @@ -46,19 +49,21 @@ impl<'a> Auditor<'a> {
}
author.finish()
};
// TODO: make stylesheet building optional and only on first requirement

console_log!("StyleSheets Build Time {:?}", now() - tt);

let t = now();
let tree = parse_accessibility_tree(&document, &author);

let (tree, taffy, match_context) =
parse_accessibility_tree(&document, &author, match_context);
console_log!("Tree Build Time {:?}", now() - t);

Auditor {
document,
tree,
author,
match_context,
taffy,
}
}
}
134 changes: 102 additions & 32 deletions kayle_innate/kayle_innate/src/engine/audit/tree.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
use scraper_forky::selector::Simple;
use scraper_forky::ElementRef;
use victor_tree::style::StyleSet;
use scraper_forky::Html;
use selectors::matching::MatchingContext;
use slotmap::DefaultKey;
use std::collections::BTreeMap;
use std::collections::HashSet;
use taffy::prelude::*;
use victor_tree::style::values::Direction;
use victor_tree::style::values::WritingMode;
use victor_tree::style::StyleSet;

lazy_static! {
static ref NODE_IGNORE: HashSet<&'static str> =
HashSet::from(["meta", "style", "link", "script", "head", "html"]);
}

/// try to fix all possible issues using a spec against the tree.
pub fn parse_accessibility_tree<'a, 'b>(
html: &'a Html,
_author: &StyleSet,
// todo: return the nodes with a tuple of the layout node and the element node
) -> std::collections::BTreeMap<&'a str, Vec<ElementRef<'a>>> {
// use taffy::prelude::*;
pub fn parse_accessibility_tree<'a, 'b, 'c>(
document: &'a Html,
author: &StyleSet,
match_context: MatchingContext<'c, Simple>, // todo: return the nodes with a tuple of the layout node and the element node
) -> (
BTreeMap<&'a str, Vec<(ElementRef<'a>, slotmap::DefaultKey)>>,
Taffy,
MatchingContext<'c, Simple>,
) {
// // todo: use optional variable for clips or layout creation
// let mut taffy = Taffy::new();
let mut taffy = Taffy::new();

// let header_node = taffy
// let header_node: DefaultKey = taffy
// .new_leaf(Style {
// size: Size {
// width: points(800.0),
Expand All @@ -34,44 +49,99 @@ pub fn parse_accessibility_tree<'a, 'b>(
// })
// .unwrap();

// let root_node = taffy
// .new_with_children(
// Style {
// flex_direction: FlexDirection::Column,
// size: Size {
// width: points(800.0),
// height: points(600.0),
// },
// ..Default::default()
// },
// &[header_node, body_node],
// )
// .unwrap();

// // Call compute_layout on the root of your tree to run the layout algorithm
// taffy.compute_layout(root_node, Size::MAX_CONTENT).unwrap();
// console_log!("Header Layout {:?}", taffy.layout(header_node).unwrap());
// We can get the x,y, and height, width of the element on proper tree insert

// parse doc will start from html downwards
// accessibility tree for ordered element mappings
let mut accessibility_tree: BTreeMap<&str, Vec<ElementRef<'_>>> =
let mut accessibility_tree: BTreeMap<&str, Vec<(ElementRef<'_>, DefaultKey)>> =
BTreeMap::from([("title".into(), Default::default())]);

for node in html.tree.nodes() {
let mut layout_leafs: Vec<Node> = vec![];

// let mut _match_context = match_context;

let mut matching_context = match_context;
let writing_direction = (WritingMode::HorizontalTb, Direction::Ltr);

// push taffy layout in order from elements
for node in document.tree.nodes() {
match scraper_forky::element_ref::ElementRef::wrap(node) {
Some(element) => {
let name = element.value().name();
// TODO: determine if children are found to get entire layout of children to vector first
let layout_leaf = taffy
.new_leaf(Style {
// make nodes optional but, for now max out perf drawbacks
size: if NODE_IGNORE.contains(name) {
Size {
width: points(0.0),
height: points(0.0),
}
} else {
// get the layout size from computed styles
let style = victor_tree::style::cascade::style_for_element_ref(
&element,
&author,
&document,
&mut matching_context,
);
let style = style.as_ref();
let _physical_size =
style.box_size().size_to_physical(writing_direction);
// TODO: Build physical styles of each element as needed
// crate::console_log!("{name} {:?}", physical_size);
// crate::console_log!("{name} Margin {:?}", style.margin());
// crate::console_log!("{name} Padding {:?}", style.padding());
let padding_insent = style.padding().block_start;
// todo: make method to get entire size
let _padding_pxs = padding_insent.inner_px();
// crate::console_log!("{name} Padding Top {:?}", padding_pxs);
// IF the x and y is empty get the height based on the padding.
// If img has no height get the inherited from style width
// We may have to build the width/height if empty from paddings and margins

Size {
width: points(800.0),
height: points(100.0),
}
},
// todo: get entire styles up front
flex_grow: if name == "body" { 1.0 } else { 0.0 },
..Default::default()
})
.unwrap();

layout_leafs.push(layout_leaf.clone());

accessibility_tree
.entry(element.value().name())
.and_modify(|n| n.push(element))
.or_insert(Vec::from([element]));
.entry(name)
.and_modify(|n| n.push((element, layout_leaf)))
.or_insert(Vec::from([(element, layout_leaf)]));
}
_ => (),
};
}

// this is slow at the moment for large leafs being mocked
let root_node = taffy
.new_with_children(
Style {
flex_direction: FlexDirection::Column,
// compute the default layout from CDP
size: Size {
width: points(800.0),
height: points(600.0),
},
..Default::default()
},
&layout_leafs,
)
.unwrap();

taffy.compute_layout(root_node, Size::MAX_CONTENT).unwrap();
// crate::console_log!("Last Element Position {:?}", taffy.layout(layout_leafs[layout_leafs.len() - 1]).unwrap());
// console_log!("Getting tree links {:?}", accessibility_tree.get("a"));
// console_log!("Tree {:?}", accessibility_tree);

accessibility_tree
(accessibility_tree, taffy, matching_context)
}
10 changes: 8 additions & 2 deletions kayle_innate/kayle_innate/src/engine/rules/rule.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use slotmap::DefaultKey;

use crate::engine::rules::ids::Techniques;
use crate::engine::rules::wcag_base::{Criteria, Guideline, Principle};
use crate::ElementRef;
Expand All @@ -9,7 +11,8 @@ pub struct Rule {
/// the type of rule
pub criteria: Criteria,
/// validate a test returns (valid, rule, selectors)
pub validate: fn(&str, &Vec<ElementRef<'_>>) -> (bool, &'static str, Vec<&'static str>),
pub validate:
fn(&str, &Vec<(ElementRef<'_>, DefaultKey)>) -> (bool, &'static str, Vec<&'static str>),
/// the principle type
pub principle: Principle,
/// the guideline to follow
Expand All @@ -23,7 +26,10 @@ impl Rule {
criteria: Criteria,
principle: Principle,
guideline: Guideline,
validate: fn(&str, &Vec<ElementRef<'_>>) -> (bool, &'static str, Vec<&'static str>),
validate: fn(
&str,
&Vec<(ElementRef<'_>, DefaultKey)>,
) -> (bool, &'static str, Vec<&'static str>),
) -> Rule {
Rule {
rule_id,
Expand Down
3 changes: 2 additions & 1 deletion kayle_innate/kayle_innate/src/engine/rules/wcag_rule_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ lazy_static! {
(!nodes.is_empty(), "1.NoTitleEl", Default::default())
}),
Rule::new(Techniques::H25, Criteria::Error, Principle::Understandable, Guideline::Predictable, |_rule, nodes| {
(nodes.is_empty() || nodes[0].html().is_empty(), "2", Default::default())
(nodes.is_empty() || nodes[0].0.html().is_empty(), "2", Default::default())
}),
])),
// missing label
Expand All @@ -26,6 +26,7 @@ lazy_static! {
let selector = unsafe { Selector::parse("button[type=submit]").unwrap_unchecked() };

for ele in nodes {
let ele = ele.0;
valid = match ele.select(&selector).next() {
Some(_) => true,
_ => false
Expand Down
2 changes: 1 addition & 1 deletion kayle_innate/kayle_innate/src/engine/styles/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pub mod css_cache;
pub mod errors;
pub mod rules;
pub mod rules;
10 changes: 10 additions & 0 deletions kayle_innate/kayle_victor/victor/src/style/values/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ pub enum LengthOrPercentage {
Percentage(Percentage),
}

impl LengthOrPercentage {
/// get the px values as a float
pub fn inner_px(&self) -> f32 {
match self {
LengthOrPercentage::Length(l) => l.px,
LengthOrPercentage::Percentage(l) => l.unit_value,
}
}
}

#[derive(Clone, Parse, FromVariants)]
pub enum SpecifiedLengthOrPercentageOrAuto {
Length(SpecifiedLength),
Expand Down

0 comments on commit 62b7a91

Please sign in to comment.