use scraper::{Html, Node, Selector};
use oxipdf_ir::style::ResolvedStyle;
use crate::css::{CssRule, Declaration, Specificity, apply_declarations};
fn find_matching_rules<'a>(
document: &Html,
node_id: ego_tree::NodeId,
rules: &'a [CssRule],
) -> Vec<(&'a CssRule, Specificity)> {
let mut matching: Vec<(&CssRule, Specificity)> = Vec::new();
for rule in rules {
if let Ok(selector) = Selector::parse(&rule.selector) {
if let Some(el_ref) = document.tree.get(node_id) {
if let Node::Element(_) = el_ref.value() {
if let Some(el) = scraper::ElementRef::wrap(el_ref) {
if selector.matches(&el) {
matching.push((rule, rule.specificity));
}
}
}
}
}
}
matching.sort_by_key(|(_, spec)| *spec);
matching
}
pub(crate) fn apply_normal_stylesheet_rules(
document: &Html,
node_id: ego_tree::NodeId,
style: &mut ResolvedStyle,
rules: &[CssRule],
) {
let matching = find_matching_rules(document, node_id, rules);
for (rule, _) in &matching {
let normal: Vec<Declaration> = rule
.declarations
.iter()
.filter(|d| !d.important)
.cloned()
.collect();
if !normal.is_empty() {
apply_declarations(style, &normal);
}
}
}
pub(crate) fn apply_important_stylesheet_rules(
document: &Html,
node_id: ego_tree::NodeId,
style: &mut ResolvedStyle,
rules: &[CssRule],
) {
let matching = find_matching_rules(document, node_id, rules);
for (rule, _) in &matching {
let important: Vec<Declaration> = rule
.declarations
.iter()
.filter(|d| d.important)
.cloned()
.collect();
if !important.is_empty() {
apply_declarations(style, &important);
}
}
}
pub(crate) fn apply_matching_rules(
document: &Html,
node_id: ego_tree::NodeId,
style: &mut ResolvedStyle,
rules: &[CssRule],
) {
let matching = find_matching_rules(document, node_id, rules);
for (rule, _) in &matching {
let normal: Vec<Declaration> = rule
.declarations
.iter()
.filter(|d| !d.important)
.cloned()
.collect();
if !normal.is_empty() {
apply_declarations(style, &normal);
}
}
for (rule, _) in &matching {
let important: Vec<Declaration> = rule
.declarations
.iter()
.filter(|d| d.important)
.cloned()
.collect();
if !important.is_empty() {
apply_declarations(style, &important);
}
}
}