use markup5ever::QualName;
use std::cell::{Ref, RefMut};
use std::fmt;
use std::rc::Rc;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::{DrawingCtx, Viewport};
use crate::element::*;
use crate::error::*;
use crate::paint_server::PaintSource;
use crate::properties::ComputedValues;
use crate::rsvg_log;
use crate::session::Session;
use crate::text::Chars;
use crate::xml::Attributes;
pub type Node = rctree::Node<NodeData>;
pub type WeakNode = rctree::WeakNode<NodeData>;
pub enum NodeData {
Element(Box<Element>),
Text(Box<Chars>),
}
impl NodeData {
pub fn new_element(session: &Session, name: &QualName, attrs: Attributes) -> NodeData {
NodeData::Element(Box::new(Element::new(session, name, attrs)))
}
pub fn new_chars(initial_text: &str) -> NodeData {
NodeData::Text(Box::new(Chars::new(initial_text)))
}
}
impl fmt::Display for NodeData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
NodeData::Element(ref e) => {
write!(f, "{e}")?;
}
NodeData::Text(_) => {
write!(f, "Chars")?;
}
}
Ok(())
}
}
pub struct CascadedValues<'a> {
inner: CascadedInner<'a>,
pub context_stroke: Option<Rc<PaintSource>>,
pub context_fill: Option<Rc<PaintSource>>,
}
enum CascadedInner<'a> {
FromNode(Ref<'a, Element>),
FromValues(Box<ComputedValues>),
}
impl<'a> CascadedValues<'a> {
pub fn clone_with_node(&self, node: &'a Node) -> CascadedValues<'a> {
match self.inner {
CascadedInner::FromNode(_) => CascadedValues {
inner: CascadedInner::FromNode(node.borrow_element()),
context_fill: self.context_fill.clone(),
context_stroke: self.context_stroke.clone(),
},
CascadedInner::FromValues(ref v) => CascadedValues::new_from_values(
node,
v,
self.context_fill.clone(),
self.context_stroke.clone(),
),
}
}
pub fn new_from_node(node: &Node) -> CascadedValues<'_> {
CascadedValues {
inner: CascadedInner::FromNode(node.borrow_element()),
context_fill: None,
context_stroke: None,
}
}
pub fn new_from_values(
node: &'a Node,
values: &ComputedValues,
fill: Option<Rc<PaintSource>>,
stroke: Option<Rc<PaintSource>>,
) -> CascadedValues<'a> {
let mut v = Box::new(values.clone());
node.borrow_element()
.get_specified_values()
.to_computed_values(&mut v);
CascadedValues {
inner: CascadedInner::FromValues(v),
context_fill: fill,
context_stroke: stroke,
}
}
pub fn get(&'a self) -> &'a ComputedValues {
match self.inner {
CascadedInner::FromNode(ref e) => e.get_computed_values(),
CascadedInner::FromValues(ref v) => v,
}
}
}
pub trait NodeBorrow {
fn is_element(&self) -> bool;
fn is_chars(&self) -> bool;
fn borrow_chars(&self) -> Ref<'_, Chars>;
fn borrow_element(&self) -> Ref<'_, Element>;
fn borrow_element_mut(&mut self) -> RefMut<'_, Element>;
fn borrow_element_data(&self) -> Ref<'_, ElementData>;
}
impl NodeBorrow for Node {
fn is_element(&self) -> bool {
matches!(*self.borrow(), NodeData::Element(_))
}
fn is_chars(&self) -> bool {
matches!(*self.borrow(), NodeData::Text(_))
}
fn borrow_chars(&self) -> Ref<'_, Chars> {
Ref::map(self.borrow(), |n| match n {
NodeData::Text(c) => &**c,
_ => panic!("tried to borrow_chars for a non-text node"),
})
}
fn borrow_element(&self) -> Ref<'_, Element> {
Ref::map(self.borrow(), |n| match n {
NodeData::Element(e) => &**e,
_ => panic!("tried to borrow_element for a non-element node"),
})
}
fn borrow_element_mut(&mut self) -> RefMut<'_, Element> {
RefMut::map(self.borrow_mut(), |n| match &mut *n {
NodeData::Element(e) => &mut **e,
_ => panic!("tried to borrow_element_mut for a non-element node"),
})
}
fn borrow_element_data(&self) -> Ref<'_, ElementData> {
Ref::map(self.borrow(), |n| match n {
NodeData::Element(e) => &e.element_data,
_ => panic!("tried to borrow_element_data for a non-element node"),
})
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! is_element_of_type {
($node:expr, $element_type:ident) => {
matches!(
$node.borrow_element().element_data,
$crate::element::ElementData::$element_type(_)
)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! borrow_element_as {
($node:expr, $element_type:ident) => {
std::cell::Ref::map($node.borrow_element_data(), |d| match d {
&$crate::element::ElementData::$element_type(ref e) => &*e,
_ => panic!("tried to borrow_element_as {}", stringify!($element_type)),
})
};
}
pub trait NodeCascade {
fn cascade(&mut self, values: &ComputedValues);
}
impl NodeCascade for Node {
fn cascade(&mut self, values: &ComputedValues) {
let mut values = Box::new(values.clone());
{
let mut elt = self.borrow_element_mut();
elt.get_specified_values().to_computed_values(&mut values);
elt.set_computed_values(&values);
}
for mut child in self.children().filter(|c| c.is_element()) {
child.cascade(&values);
}
}
}
pub trait NodeDraw {
fn draw(
&self,
acquired_nodes: &mut AcquiredNodes<'_>,
cascaded: &CascadedValues<'_>,
viewport: &Viewport,
draw_ctx: &mut DrawingCtx,
clipping: bool,
) -> DrawResult;
fn draw_children(
&self,
acquired_nodes: &mut AcquiredNodes<'_>,
cascaded: &CascadedValues<'_>,
viewport: &Viewport,
draw_ctx: &mut DrawingCtx,
clipping: bool,
) -> DrawResult;
}
impl NodeDraw for Node {
fn draw(
&self,
acquired_nodes: &mut AcquiredNodes<'_>,
cascaded: &CascadedValues<'_>,
viewport: &Viewport,
draw_ctx: &mut DrawingCtx,
clipping: bool,
) -> DrawResult {
match *self.borrow() {
NodeData::Element(ref e) => {
rsvg_log!(draw_ctx.session(), "({}", e);
draw_ctx.print_stack_depth("Node::draw");
let res = match e.draw(self, acquired_nodes, cascaded, viewport, draw_ctx, clipping)
{
Ok(bbox) => Ok(bbox),
Err(boxed_e) => match *boxed_e {
InternalRenderingError::InvalidTransform => Ok(viewport.empty_bbox()),
InternalRenderingError::CircularReference(node) => {
if node != *self {
return Ok(viewport.empty_bbox());
} else {
return Err(Box::new(InternalRenderingError::CircularReference(
node,
)));
}
}
_ => Err(boxed_e),
},
};
rsvg_log!(draw_ctx.session(), ")");
res
}
_ => Ok(viewport.empty_bbox()),
}
}
fn draw_children(
&self,
acquired_nodes: &mut AcquiredNodes<'_>,
cascaded: &CascadedValues<'_>,
viewport: &Viewport,
draw_ctx: &mut DrawingCtx,
clipping: bool,
) -> DrawResult {
draw_ctx.print_stack_depth("Node::draw_children");
let mut bbox = viewport.empty_bbox();
for child in self.children().filter(|c| c.is_element()) {
let child_bbox = draw_ctx.draw_node_from_stack(
&child,
acquired_nodes,
&CascadedValues::clone_with_node(cascaded, &child),
viewport,
clipping,
)?;
bbox.insert(&child_bbox);
}
Ok(bbox)
}
}