use crate::bitset::BitSet;
use crate::draw::Patch;
use crate::style::{Declaration, FontId, ImageId, PatchId, Selector, Style, StyleState};
use crate::text::Font;
use crate::widget::image::ImageData;
use std::collections::{HashMap, VecDeque};
use std::iter::FromIterator;
use std::sync::Arc;
#[derive(Debug, Default)]
pub(crate) struct RuleTree {
rules: Vec<Rule>,
}
#[derive(Debug)]
pub(crate) struct Rule {
selector: Selector,
declarations: Vec<Declaration<ImageData, Patch, Font>>,
children: Vec<usize>,
}
#[derive(Debug)]
pub(crate) struct RuleTreeBuilder {
pub selector: Selector,
pub declarations: Vec<Declaration<ImageId, PatchId, FontId>>,
pub children: Vec<RuleTreeBuilder>,
}
#[derive(Clone)]
pub struct Query {
pub style: Arc<Style>,
pub ancestors: Vec<BitSet>,
pub siblings: Vec<BitSet>,
}
impl RuleTree {
pub fn iter_declarations<'a>(
&'a self,
style: &'a BitSet,
) -> impl Iterator<Item = &'a Declaration<ImageData, Patch, Font>> {
style.iter().flat_map(move |rule| self.rules[rule].declarations.iter())
}
pub fn add_to_bitset<S: AsRef<str>>(
&self,
rule: usize,
state: &[StyleState<S>],
class: &str,
n: usize,
len: usize,
to: &mut BitSet,
) {
to.insert(rule);
for &child_rule in self.rules[rule].children.iter() {
if self.rules[child_rule]
.selector
.match_meta(state, class, n, len)
.unwrap_or(false)
{
self.add_to_bitset(child_rule, state, class, n, len, to);
}
}
}
pub fn match_child<'a>(&'a self, rule: usize, direct: bool, widget: &'a str) -> impl 'a + Iterator<Item = usize> {
self.rules[rule].children.iter().cloned().filter(move |&child_rule| {
self.rules[child_rule]
.selector
.match_child(direct, widget)
.unwrap_or(false)
})
}
pub fn match_sibling<'a>(&'a self, rule: usize, direct: bool, widget: &'a str) -> impl 'a + Iterator<Item = usize> {
self.rules[rule].children.iter().cloned().filter(move |&child_rule| {
self.rules[child_rule]
.selector
.match_sibling(direct, widget)
.unwrap_or(false)
})
}
pub fn rematch<S: AsRef<str>>(
&self,
style: &BitSet,
state: &[StyleState<S>],
class: &str,
n: usize,
len: usize,
) -> BitSet {
let mut result = BitSet::new();
for selector in style.iter().filter(|&selector| {
self.rules[selector]
.selector
.match_meta(state, class, n, len)
.unwrap_or( true)
}) {
self.add_to_bitset(selector, state, class, n, len, &mut result);
}
result
}
}
impl RuleTreeBuilder {
pub fn new() -> Self {
RuleTreeBuilder {
selector: Selector::Root,
declarations: Vec::new(),
children: Vec::new(),
}
}
pub fn insert(&mut self, selectors: impl AsRef<[Selector]>, rules: Vec<Declaration<ImageId, PatchId, FontId>>) {
self.select(selectors).declarations.extend(rules);
}
pub fn select(&mut self, selectors: impl AsRef<[Selector]>) -> &mut Self {
match selectors.as_ref().get(0) {
None => self,
Some(selector) => {
let mut index = self.children.len();
for (i, node) in self.children.iter().enumerate() {
if &node.selector == selector {
index = i;
break;
}
}
if index == self.children.len() {
self.children.push(RuleTreeBuilder {
selector: selector.clone(),
declarations: Vec::new(),
children: Vec::new(),
});
}
self.children[index].select(&selectors.as_ref()[1..])
}
}
}
pub fn merge(&mut self, mut rule_tree: Self) {
assert_eq!(self.selector, rule_tree.selector);
self.declarations.append(&mut rule_tree.declarations);
for sub_tree in rule_tree.children {
if let Some(child) = self.children.iter_mut().find(|c| c.selector == sub_tree.selector) {
child.merge(sub_tree);
} else {
self.children.push(sub_tree);
}
}
}
pub(crate) fn build(
self,
images: &HashMap<String, ImageData>,
patches: &HashMap<String, Patch>,
fonts: &HashMap<String, Font>,
) -> RuleTree {
let mut rules = Vec::<Rule>::new();
let mut queue = VecDeque::new();
queue.push_back((self, None));
while let Some((rule, parent)) = queue.pop_front() {
for child in rule.children {
queue.push_back((child, Some(rules.len())));
}
if let Some(parent) = parent {
let child = rules.len();
rules[parent].children.push(child);
}
rules.push(Rule {
selector: rule.selector,
declarations: rule
.declarations
.into_iter()
.map(|declaration| match declaration {
Declaration::BackgroundNone => Declaration::BackgroundNone,
Declaration::BackgroundColor(x) => Declaration::BackgroundColor(x),
Declaration::BackgroundImage(ImageId(x), y) => {
Declaration::BackgroundImage(images[&x].clone(), y)
}
Declaration::BackgroundPatch(PatchId(x), y) => {
Declaration::BackgroundPatch(patches[&x].clone(), y)
}
Declaration::Font(FontId(x)) => Declaration::Font(fonts[&x].clone()),
Declaration::Color(x) => Declaration::Color(x),
Declaration::Padding(x) => Declaration::Padding(x),
Declaration::PaddingLeft(x) => Declaration::PaddingLeft(x),
Declaration::PaddingRight(x) => Declaration::PaddingRight(x),
Declaration::PaddingTop(x) => Declaration::PaddingTop(x),
Declaration::PaddingBottom(x) => Declaration::PaddingBottom(x),
Declaration::Margin(x) => Declaration::Margin(x),
Declaration::MarginLeft(x) => Declaration::MarginLeft(x),
Declaration::MarginRight(x) => Declaration::MarginRight(x),
Declaration::MarginTop(x) => Declaration::MarginTop(x),
Declaration::MarginBottom(x) => Declaration::MarginBottom(x),
Declaration::TextSize(x) => Declaration::TextSize(x),
Declaration::TextWrap(x) => Declaration::TextWrap(x),
Declaration::Width(x) => Declaration::Width(x),
Declaration::Height(x) => Declaration::Height(x),
Declaration::LayoutDirection(x) => Declaration::LayoutDirection(x),
Declaration::AlignHorizontal(x) => Declaration::AlignHorizontal(x),
Declaration::AlignVertical(x) => Declaration::AlignVertical(x),
Declaration::AddFlag(x) => Declaration::AddFlag(x),
Declaration::RemoveFlag(x) => Declaration::RemoveFlag(x),
})
.collect(),
children: Vec::new(),
});
}
RuleTree { rules }
}
}
impl Default for RuleTreeBuilder {
fn default() -> Self {
Self::new()
}
}
impl Query {
pub fn from_style(style: Arc<Style>) -> Self {
Self {
style,
ancestors: vec![BitSet::from_iter(Some(0))],
siblings: Vec::new(),
}
}
pub fn match_widget<S: AsRef<str>>(
&self,
widget: &str,
class: &str,
state: &[StyleState<S>],
n: usize,
len: usize,
) -> BitSet {
let mut result = BitSet::new();
let from_ancestors = self.ancestors.iter().rev().enumerate().flat_map(move |(i, matches)| {
matches
.iter()
.flat_map(move |node| self.style.rule_tree.match_child(node, i == 0, widget))
});
let from_siblings = self.siblings.iter().rev().enumerate().flat_map(move |(i, matches)| {
matches
.iter()
.flat_map(move |node| self.style.rule_tree.match_sibling(node, i == 0, widget))
});
for node in from_ancestors.chain(from_siblings) {
self.style
.rule_tree
.add_to_bitset(node, state, class, n, len, &mut result);
}
result
}
}