the aliasing svg renderer
Diffstat (limited to 'src/tree.rs')
-rw-r--r--src/tree.rs195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/tree.rs b/src/tree.rs
new file mode 100644
index 0000000..4aa2aab
--- /dev/null
+++ b/src/tree.rs
@@ -0,0 +1,195 @@
+use anyhow::Result;
+use tiny_skia_path::{NonZeroPositiveF32, NormalizedF32, Path, Rect, Size, Transform};
+use usvg::{BBox, Color, Fill, Image, Opacity, Options, Paint, TreeParsing};
+
+#[derive(Debug)]
+pub struct Tree {
+ pub width: f32,
+ pub height: f32,
+ pub children: Box<[Node]>,
+ pub osize: Size,
+}
+
+#[derive(Debug)]
+pub enum PathNode {
+ Fill {
+ color: Color,
+ opacity: Opacity,
+ path: Path,
+ },
+ Stroke {
+ color: Color,
+ opacity: Opacity,
+ stroke_color: Color,
+ stroke_opacity: Opacity,
+ stroke: NonZeroPositiveF32,
+ path: Path,
+ },
+}
+
+#[derive(Debug)]
+pub enum Node {
+ Group {
+ opacity: Opacity,
+ bbox: BBox,
+ children: Box<[Node]>,
+ },
+ Path(PathNode),
+ Image(Image),
+}
+
+impl Node {
+ fn transform(&mut self, t: Transform) {
+ match self {
+ Self::Path(PathNode::Fill { path, .. } | PathNode::Stroke { path, .. }) => {
+ *path = path.clone().transform(t).unwrap(); // idc
+ }
+ // TODO
+ _ => {}
+ }
+ }
+}
+
+impl From<usvg::Tree> for Tree {
+ fn from(tree: usvg::Tree) -> Self {
+ let mut children = vec![];
+ collect(tree.root, &mut children);
+ Self {
+ osize: tree.size,
+ width: tree.view_box.rect.width(),
+ height: tree.view_box.rect.height(),
+ children: children.into(),
+ }
+ }
+}
+
+trait PColor {
+ fn col(&self) -> Color;
+}
+
+impl PColor for Paint {
+ fn col(&self) -> Color {
+ match self {
+ Self::Color(c) => *c,
+ _ => unimplemented!(),
+ }
+ }
+}
+fn convert(node: usvg::Node, to: &mut Vec<Node>) -> Option<Rect> {
+ match &*node.clone().borrow() {
+ usvg::NodeKind::Group(g) => {
+ let mut children = vec![];
+ let bbox = collect(node, &mut children);
+ let mut children = children.into_boxed_slice();
+ for child in &mut *children {
+ child.transform(g.transform);
+ }
+ to.push(Node::Group {
+ opacity: g.opacity,
+ bbox,
+ children,
+ });
+ bbox.to_rect()
+ }
+ usvg::NodeKind::Path(usvg::Path {
+ stroke:
+ Some(usvg::Stroke {
+ paint: stroke_paint,
+ opacity: stroke_opacity,
+ width: stroke,
+ ..
+ }),
+ transform,
+ fill: Some(Fill { opacity, paint, .. }),
+ data: path,
+ ..
+ }) => {
+ to.push(Node::Path(PathNode::Stroke {
+ color: paint.col(),
+ opacity: *opacity,
+ stroke: *stroke,
+ stroke_opacity: *stroke_opacity,
+ stroke_color: stroke_paint.col(),
+ path: (**path).clone().transform(*transform).unwrap(),
+ }));
+ Some(path.bounds())
+ }
+ usvg::NodeKind::Path(usvg::Path {
+ stroke:
+ Some(usvg::Stroke {
+ paint: stroke_paint,
+ opacity: stroke_opacity,
+ width: stroke,
+ ..
+ }),
+ transform,
+ fill: None,
+ data: path,
+ ..
+ }) => {
+ to.push(Node::Path(PathNode::Stroke {
+ color: Color::black(),
+ opacity: NormalizedF32::new(0.0).unwrap(),
+ stroke: *stroke,
+ stroke_opacity: *stroke_opacity,
+ stroke_color: stroke_paint.col(),
+ path: (**path).clone().transform(*transform).unwrap(),
+ }));
+ Some(path.bounds())
+ }
+ usvg::NodeKind::Path(usvg::Path {
+ transform,
+ stroke: None,
+ fill: Some(Fill { opacity, paint, .. }),
+ data: path,
+ ..
+ }) => {
+ to.push(Node::Path(PathNode::Fill {
+ color: paint.col(),
+ opacity: *opacity,
+ path: (**path).clone().transform(*transform).unwrap(),
+ }));
+ Some(path.bounds())
+ }
+ usvg::NodeKind::Path(usvg::Path {
+ transform,
+ stroke: None,
+ fill: None,
+ data: path,
+ ..
+ }) => {
+ to.push(Node::Path(PathNode::Fill {
+ color: Color::black(),
+ opacity: NormalizedF32::new(0.0).unwrap(),
+ path: (**path).clone().transform(*transform).unwrap(),
+ }));
+ Some(path.bounds())
+ }
+ usvg::NodeKind::Image(_) => todo!(),
+ usvg::NodeKind::Text(_) => unimplemented!(),
+ }
+}
+
+fn collect(node: usvg::Node, to: &mut Vec<Node>) -> BBox {
+ let mut bbox = BBox::default();
+ for child in node.children() {
+ bbox = bbox.expand(collect(child.clone(), to));
+ bbox = bbox.expand(convert(child, to).map_or(BBox::default(), BBox::from));
+ }
+ bbox
+}
+
+impl Tree {
+ pub fn new(svg: &str) -> Result<Self> {
+ Ok(Tree::from(usvg::Tree::from_str(svg, &Options::default())?))
+ }
+
+ pub fn resize(&mut self, w: f32, h: f32) {
+ let t = Transform::from_scale(w / self.width, h / self.height);
+ for child in &mut *self.children {
+ child.transform(t);
+ }
+ self.width = w;
+ self.height = h;
+ }
+}