mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-09 20:31:29 +11:00
Merge branch 'more_svg' into new_merge
This commit is contained in:
commit
c603cafc6c
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::str::FromStr;
|
||||
|
||||
use roxmltree::Document;
|
||||
use roxmltree::{Document, Node};
|
||||
|
||||
use piet::kurbo::{Affine, BezPath};
|
||||
|
||||
|
@ -28,31 +28,18 @@ pub struct FillItem {
|
|||
path: BezPath,
|
||||
}
|
||||
|
||||
struct Parser<'a> {
|
||||
items: &'a mut Vec<Item>,
|
||||
}
|
||||
|
||||
impl PicoSvg {
|
||||
pub fn load(xml_string: &str, scale: f64) -> Result<PicoSvg, Box<dyn std::error::Error>> {
|
||||
let doc = Document::parse(xml_string)?;
|
||||
let root = doc.root_element();
|
||||
let g = root.first_element_child().ok_or("no root element")?;
|
||||
let mut items = Vec::new();
|
||||
for el in g.children() {
|
||||
if el.is_element() {
|
||||
let d = el.attribute("d").ok_or("missing 'd' attribute")?;
|
||||
let bp = BezPath::from_svg(d)?;
|
||||
let path = Affine::scale(scale) * bp;
|
||||
if let Some(fill_color) = el.attribute("fill") {
|
||||
let color = parse_color(fill_color);
|
||||
items.push(Item::Fill(FillItem {
|
||||
color,
|
||||
path: path.clone(),
|
||||
}));
|
||||
}
|
||||
if let Some(stroke_color) = el.attribute("stroke") {
|
||||
let width =
|
||||
scale * f64::from_str(el.attribute("stroke-width").ok_or("missing width")?)?;
|
||||
let color = parse_color(stroke_color);
|
||||
items.push(Item::Stroke(StrokeItem { width, color, path }));
|
||||
}
|
||||
}
|
||||
let mut parser = Parser::new(&mut items);
|
||||
for node in root.children() {
|
||||
parser.rec_parse(node)?;
|
||||
}
|
||||
Ok(PicoSvg { items })
|
||||
}
|
||||
|
@ -72,6 +59,49 @@ impl PicoSvg {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn new(items: &'a mut Vec<Item>) -> Parser<'a> {
|
||||
Parser {
|
||||
items
|
||||
}
|
||||
}
|
||||
|
||||
fn rec_parse(&mut self, node: Node) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if node.is_element() {
|
||||
match node.tag_name().name() {
|
||||
"g" => {
|
||||
for child in node.children() {
|
||||
self.rec_parse(child)?;
|
||||
}
|
||||
}
|
||||
"path" => {
|
||||
let d = node.attribute("d").ok_or("missing 'd' attribute")?;
|
||||
let bp = BezPath::from_svg(d)?;
|
||||
let path = Affine::new([1.5, 0.0, 0.0, -1.5, 0.0, 1500.0]) * bp;
|
||||
// TODO: default fill color is black, but this is overridden in tiger to this logic.
|
||||
if let Some(fill_color) = node.attribute("fill") {
|
||||
if fill_color != "none" {
|
||||
let color = parse_color(fill_color);
|
||||
let color = modify_opacity(color, "fill-opacity", node);
|
||||
self.items.push(Item::Fill(FillItem { color, path: path.clone() }));
|
||||
}
|
||||
}
|
||||
if let Some(stroke_color) = node.attribute("stroke") {
|
||||
if stroke_color != "none" {
|
||||
let width = 1.5 * f64::from_str(node.attribute("stroke-width").ok_or("missing width")?)?;
|
||||
let color = parse_color(stroke_color);
|
||||
let color = modify_opacity(color, "stroke-opacity", node);
|
||||
self.items.push(Item::Stroke(StrokeItem { width, color, path }));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_color(color: &str) -> Color {
|
||||
if color.as_bytes()[0] == b'#' {
|
||||
let mut hex = u32::from_str_radix(&color[1..], 16).unwrap();
|
||||
|
@ -79,7 +109,27 @@ fn parse_color(color: &str) -> Color {
|
|||
hex = (hex >> 8) * 0x110000 + ((hex >> 4) & 0xf) * 0x1100 + (hex & 0xf) * 0x11;
|
||||
}
|
||||
Color::from_rgba32_u32((hex << 8) + 0xff)
|
||||
} else if color.starts_with("rgb(") {
|
||||
let mut iter = color[4..color.len() - 1].split(',');
|
||||
let r = u8::from_str(iter.next().unwrap()).unwrap();
|
||||
let g = u8::from_str(iter.next().unwrap()).unwrap();
|
||||
let b = u8::from_str(iter.next().unwrap()).unwrap();
|
||||
Color::rgb8(r, g, b)
|
||||
} else {
|
||||
Color::from_rgba32_u32(0xff00ff80)
|
||||
}
|
||||
}
|
||||
|
||||
fn modify_opacity(color: Color, attr_name: &str, node: Node) -> Color {
|
||||
if let Some(opacity) = node.attribute(attr_name) {
|
||||
let alpha = if opacity.ends_with("%") {
|
||||
let pctg = opacity[..opacity.len() - 1].parse().unwrap_or(100.0);
|
||||
pctg * 0.01
|
||||
} else {
|
||||
opacity.parse().unwrap_or(1.0)
|
||||
};
|
||||
color.with_alpha(alpha)
|
||||
} else {
|
||||
color
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue