diff --git a/crates/resvg/examples/custom_href_resolver.rs b/crates/resvg/examples/custom_href_resolver.rs index 7e6544dbe..67b86baee 100644 --- a/crates/resvg/examples/custom_href_resolver.rs +++ b/crates/resvg/examples/custom_href_resolver.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use usvg::TreeParsing; fn main() { @@ -6,11 +8,11 @@ fn main() { let ferris_image = std::sync::Arc::new(std::fs::read("./examples/ferris.png").unwrap()); // We know that our SVG won't have DataUrl hrefs, just return None for such case. - let resolve_data = Box::new(|_: &str, _: std::sync::Arc>, _: &usvg::Options| None); + let resolve_data = Arc::new(|_: &str, _: std::sync::Arc>, _: &usvg::Options| None); // Here we handle xlink:href attribute as string, // let's use already loaded Ferris image to match that string. - let resolve_string = Box::new(move |href: &str, _: &usvg::Options| match href { + let resolve_string = Arc::new(move |href: &str, _: &usvg::Options| match href { "ferris_image" => Some(usvg::ImageKind::PNG(ferris_image.clone())), _ => None, }); diff --git a/crates/resvg/examples/custom_usvg_tree.rs b/crates/resvg/examples/custom_usvg_tree.rs index 2153f817f..6b82939a9 100644 --- a/crates/resvg/examples/custom_usvg_tree.rs +++ b/crates/resvg/examples/custom_usvg_tree.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; fn main() { let size = usvg::Size::from_wh(200.0, 200.0).unwrap(); @@ -37,11 +37,12 @@ fn main() { }; let fill = Some(usvg::Fill { - paint: usvg::Paint::LinearGradient(Rc::new(gradient)), + paint: usvg::Paint::LinearGradient(Arc::new(gradient)), ..usvg::Fill::default() }); - let mut path = usvg::Path::new(Rc::new(tiny_skia::PathBuilder::from_rect( + + let mut path = usvg::Path::new(Arc::new(tiny_skia::PathBuilder::from_rect( tiny_skia::Rect::from_xywh(20.0, 20.0, 160.0, 160.0).unwrap(), ))); path.fill = fill; diff --git a/crates/resvg/examples/draw_bboxes.rs b/crates/resvg/examples/draw_bboxes.rs index 1e8dbb115..15f413c20 100644 --- a/crates/resvg/examples/draw_bboxes.rs +++ b/crates/resvg/examples/draw_bboxes.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::sync::Arc; use usvg::{fontdb, NodeExt, TreeParsing, TreeTextToPath}; @@ -61,13 +61,13 @@ fn main() { }); for bbox in bboxes { - let mut path = usvg::Path::new(Rc::new(tiny_skia::PathBuilder::from_rect(bbox))); + let mut path = usvg::Path::new(Arc::new(tiny_skia::PathBuilder::from_rect(bbox))); path.stroke = stroke.clone(); tree.root.append_kind(usvg::NodeKind::Path(path)); } for bbox in text_bboxes { - let mut path = usvg::Path::new(Rc::new(tiny_skia::PathBuilder::from_rect(bbox))); + let mut path = usvg::Path::new(Arc::new(tiny_skia::PathBuilder::from_rect(bbox))); path.stroke = stroke2.clone(); tree.root.append_kind(usvg::NodeKind::Path(path)); } diff --git a/crates/resvg/src/clip.rs b/crates/resvg/src/clip.rs index 69bd6ea64..615c72ba4 100644 --- a/crates/resvg/src/clip.rs +++ b/crates/resvg/src/clip.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use crate::render::Context; use crate::tree::{Node, OptionLog}; @@ -14,7 +14,7 @@ pub struct ClipPath { } pub fn convert( - upath: Option>, + upath: Option>, object_bbox: tiny_skia::Rect, ) -> Option { let upath = upath?; diff --git a/crates/resvg/src/filter/mod.rs b/crates/resvg/src/filter/mod.rs index 855f63cbb..154e07715 100644 --- a/crates/resvg/src/filter/mod.rs +++ b/crates/resvg/src/filter/mod.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use rgb::{FromSlice, RGBA8}; use tiny_skia::IntRect; @@ -99,7 +99,7 @@ pub struct Filter { } pub fn convert( - ufilters: &[Rc], + ufilters: &[Arc], object_bbox: Option, ) -> (Vec, Option) { let object_bbox = object_bbox.and_then(|bbox| bbox.to_non_zero_rect()); @@ -389,7 +389,7 @@ struct Image { /// Filter primitive result. /// /// All images have the same size which is equal to the current filter region. - image: Rc, + image: Arc, /// Image's region that has actual data. /// @@ -408,7 +408,7 @@ impl Image { fn from_image(image: tiny_skia::Pixmap, color_space: usvg::filter::ColorInterpolation) -> Self { let (w, h) = (image.width(), image.height()); Image { - image: Rc::new(image), + image: Arc::new(image), region: IntRect::from_xywh(0, 0, w, h).unwrap(), color_space, } @@ -429,7 +429,7 @@ impl Image { } Ok(Image { - image: Rc::new(image), + image: Arc::new(image), region, color_space, }) @@ -439,7 +439,7 @@ impl Image { } fn take(self) -> Result { - match Rc::try_unwrap(self.image) { + match Arc::try_unwrap(self.image) { Ok(v) => Ok(v), Err(v) => Ok((*v).clone()), } @@ -620,7 +620,7 @@ fn apply_inner( }; result = Image { - image: Rc::new(pixmap), + image: Arc::new(pixmap), region: subregion, color_space, }; @@ -652,7 +652,7 @@ fn calc_region( } pub fn calc_filters_region( - filters: &[Rc], + filters: &[Arc], object_bbox: Option, ) -> Option { let mut global_region = usvg::BBox::default(); @@ -738,7 +738,7 @@ fn get_input( let image = source.clone(); Ok(Image { - image: Rc::new(image), + image: Arc::new(image), region, color_space: usvg::filter::ColorInterpolation::SRGB, }) @@ -753,7 +753,7 @@ fn get_input( } Ok(Image { - image: Rc::new(image), + image: Arc::new(image), region, color_space: usvg::filter::ColorInterpolation::SRGB, }) diff --git a/crates/resvg/src/image.rs b/crates/resvg/src/image.rs index e3c50b5ab..19ab0bf69 100644 --- a/crates/resvg/src/image.rs +++ b/crates/resvg/src/image.rs @@ -36,7 +36,7 @@ pub fn convert(image: &usvg::Image, children: &mut Vec) -> Option } let kind = match image.kind { - usvg::ImageKind::SVG(ref utree) => ImageKind::Vector(Tree::from_usvg(utree)), + usvg::ImageKind::SVG(_) => return None, #[cfg(feature = "raster-images")] _ => ImageKind::Raster(raster_images::decode_raster(image)?), #[cfg(not(feature = "raster-images"))] @@ -108,6 +108,8 @@ fn render_vector( #[cfg(feature = "raster-images")] mod raster_images { + use usvg::fontdb::Database; + use super::Image; use crate::render::TinySkiaPixmapMutExt; use crate::tree::OptionLog; @@ -124,6 +126,9 @@ mod raster_images { usvg::ImageKind::GIF(ref data) => { decode_gif(data).log_none(|| log::warn!("Failed to decode a GIF image.")) } + usvg::ImageKind::RAW(w, h, ref data) => { + tiny_skia::Pixmap::from_vec((&**data).clone(), tiny_skia::IntSize::from_wh(w, h)?) + } } } diff --git a/crates/resvg/src/mask.rs b/crates/resvg/src/mask.rs index ea15131b3..34f75e751 100644 --- a/crates/resvg/src/mask.rs +++ b/crates/resvg/src/mask.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use crate::render::Context; use crate::tree::{Node, OptionLog}; @@ -16,7 +16,7 @@ pub struct Mask { pub children: Vec, } -pub fn convert(umask: Option>, object_bbox: tiny_skia::Rect) -> Option { +pub fn convert(umask: Option>, object_bbox: tiny_skia::Rect) -> Option { let umask = umask?; let mut content_transform = tiny_skia::Transform::default(); diff --git a/crates/resvg/src/path.rs b/crates/resvg/src/path.rs index 25017afea..5111a6733 100644 --- a/crates/resvg/src/path.rs +++ b/crates/resvg/src/path.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use crate::paint_server::Paint; use crate::render::Context; @@ -13,7 +13,7 @@ pub struct FillPath { pub paint: Paint, pub rule: tiny_skia::FillRule, pub anti_alias: bool, - pub path: Rc, + pub path: Arc, } pub struct StrokePath { @@ -21,7 +21,7 @@ pub struct StrokePath { pub paint: Paint, pub stroke: tiny_skia::Stroke, pub anti_alias: bool, - pub path: Rc, + pub path: Arc, } pub fn convert(upath: &usvg::Path, children: &mut Vec) -> Option { @@ -94,7 +94,7 @@ pub fn convert(upath: &usvg::Path, children: &mut Vec) -> Option { fn convert_fill_path( ufill: &usvg::Fill, - path: Rc, + path: Arc, transform: tiny_skia::Transform, text_bbox: Option, anti_alias: bool, @@ -130,7 +130,7 @@ fn convert_fill_path( fn convert_stroke_path( ustroke: &usvg::Stroke, - path: Rc, + path: Arc, transform: tiny_skia::Transform, text_bbox: Option, anti_alias: bool, diff --git a/crates/usvg-parser/src/clippath.rs b/crates/usvg-parser/src/clippath.rs index 45cd1ae66..a3a5c1a6a 100644 --- a/crates/usvg-parser/src/clippath.rs +++ b/crates/usvg-parser/src/clippath.rs @@ -2,8 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; use std::str::FromStr; +use std::sync::Arc; use usvg_tree::{ClipPath, Group, Node, NodeKind, Transform, Units}; @@ -14,7 +14,7 @@ pub(crate) fn convert( node: SvgNode, state: &converter::State, cache: &mut converter::Cache, -) -> Option> { +) -> Option> { // A `clip-path` attribute must reference a `clipPath` element. if node.tag_name() != Some(EId::ClipPath) { return None; @@ -56,7 +56,7 @@ pub(crate) fn convert( converter::convert_clip_path_elements(node, &clip_state, cache, &mut clip.root); if clip.root.has_children() { - let clip = Rc::new(clip); + let clip = Arc::new(clip); cache .clip_paths .insert(node.element_id().to_string(), clip.clone()); diff --git a/crates/usvg-parser/src/converter.rs b/crates/usvg-parser/src/converter.rs index c85b38229..0161b07e8 100644 --- a/crates/usvg-parser/src/converter.rs +++ b/crates/usvg-parser/src/converter.rs @@ -4,8 +4,8 @@ use std::collections::{HashMap, HashSet}; use std::hash::{Hash, Hasher}; -use std::rc::Rc; use std::str::FromStr; +use std::sync::Arc; use svgtypes::{Length, LengthUnit as Unit}; use usvg_tree::*; @@ -30,9 +30,9 @@ pub struct State<'a> { #[derive(Default)] pub struct Cache { - pub clip_paths: HashMap>, - pub masks: HashMap>, - pub filters: HashMap>, + pub clip_paths: HashMap>, + pub masks: HashMap>, + pub filters: HashMap>, pub paint: HashMap, // used for ID generation @@ -642,7 +642,7 @@ fn remove_empty_groups(tree: &mut Tree) { fn convert_path( node: SvgNode, - path: Rc, + path: Arc, state: &State, cache: &mut Cache, parent: &mut Node, diff --git a/crates/usvg-parser/src/filter.rs b/crates/usvg-parser/src/filter.rs index e73637ead..ed70f3b7d 100644 --- a/crates/usvg-parser/src/filter.rs +++ b/crates/usvg-parser/src/filter.rs @@ -5,8 +5,8 @@ //! A collection of SVG filters. use std::collections::HashSet; -use std::rc::Rc; use std::str::FromStr; +use std::sync::Arc; use strict_num::PositiveF32; use svgtypes::{Length, LengthUnit as Unit}; @@ -35,7 +35,7 @@ pub(crate) fn convert( node: SvgNode, state: &converter::State, cache: &mut converter::Cache, -) -> Result>, ()> { +) -> Result>, ()> { let value = match node.attribute::<&str>(AId::Filter) { Some(v) => v, None => return Ok(Vec::new()), @@ -45,7 +45,7 @@ pub(crate) fn convert( let mut filters = Vec::new(); let create_base_filter_func = - |kind, filters: &mut Vec>, cache: &mut converter::Cache| { + |kind, filters: &mut Vec>, cache: &mut converter::Cache| { // Filter functions, unlike `filter` elements, do not have a filter region. // We're currently do not support an unlimited region, so we simply use a fairly large one. // This if far from ideal, but good for now. @@ -57,7 +57,7 @@ pub(crate) fn convert( _ => NonZeroRect::from_xywh(-0.1, -0.1, 1.2, 1.2).unwrap(), }; - filters.push(Rc::new(Filter { + filters.push(Arc::new(Filter { id: cache.gen_filter_id(), units: Units::ObjectBoundingBox, primitive_units: Units::UserSpaceOnUse, @@ -156,7 +156,7 @@ fn convert_url( node: SvgNode, state: &converter::State, cache: &mut converter::Cache, -) -> Result>, ()> { +) -> Result>, ()> { if let Some(filter) = cache.filters.get(node.element_id()) { return Ok(Some(filter.clone())); } @@ -212,7 +212,7 @@ fn convert_url( return Err(()); } - let filter = Rc::new(Filter { + let filter = Arc::new(Filter { id: node.element_id().to_string(), units, primitive_units, diff --git a/crates/usvg-parser/src/image.rs b/crates/usvg-parser/src/image.rs index 9fc27e0ce..18254f6c2 100644 --- a/crates/usvg-parser/src/image.rs +++ b/crates/usvg-parser/src/image.rs @@ -12,15 +12,16 @@ use crate::{converter, OptionLog, Options, TreeParsing}; /// A shorthand for [ImageHrefResolver]'s data function. pub type ImageHrefDataResolverFn = - Box>, &Options) -> Option + Send + Sync>; + Arc>, &Options) -> Option + Send + Sync>; /// A shorthand for [ImageHrefResolver]'s string function. -pub type ImageHrefStringResolverFn = Box Option + Send + Sync>; +pub type ImageHrefStringResolverFn = Arc Option + Send + Sync>; /// An `xlink:href` resolver for `` elements. /// /// This type can be useful if you want to have an alternative `xlink:href` handling /// to the default one. For example, you can forbid access to local files (which is allowed by default) /// or add support for resolving actual URLs (usvg doesn't do any network requests). +#[derive(Clone)] pub struct ImageHrefResolver { /// Resolver function that will be used when `xlink:href` contains a /// [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs). @@ -52,11 +53,22 @@ impl ImageHrefResolver { /// Note that it will simply match the `mime` or data's magic. /// The actual images would not be decoded. It's up to the renderer. pub fn default_data_resolver() -> ImageHrefDataResolverFn { - Box::new( + Arc::new( move |mime: &str, data: Arc>, opts: &Options| match mime { "image/jpg" | "image/jpeg" => Some(ImageKind::JPEG(data)), "image/png" => Some(ImageKind::PNG(data)), "image/gif" => Some(ImageKind::GIF(data)), + "image/raw" => { + use std::io::Read; + let mut buf = data.as_slice(); + let mut width_vec = [0u8; 4]; + let mut height_vec = [0u8; 4]; + buf.read_exact(&mut width_vec).ok()?; + buf.read_exact(&mut height_vec).ok()?; + let width: u32 = u32::from_be_bytes(width_vec); + let height: u32 = u32::from_be_bytes(height_vec); + Some(ImageKind::RAW(width, height, Arc::new(buf.to_vec()))) + } "image/svg+xml" => load_sub_svg(&data, opts), "text/plain" => match get_image_data_format(&data) { Some(ImageFormat::JPEG) => Some(ImageKind::JPEG(data)), @@ -77,7 +89,7 @@ impl ImageHrefResolver { /// Paths have to be absolute or relative to the input SVG file or relative to /// [Options::resources_dir](crate::Options::resources_dir). pub fn default_string_resolver() -> ImageHrefStringResolverFn { - Box::new(move |href: &str, opts: &Options| { + Arc::new(move |href: &str, opts: &Options| { let path = opts.get_abs_path(std::path::Path::new(href)); if path.exists() { @@ -140,7 +152,21 @@ pub(crate) fn convert(node: SvgNode, state: &converter::State, parent: &mut Node .and_then(|size| Size::from_wh(size.width as f32, size.height as f32)) .log_none(|| log::warn!("Image has an invalid size. Skipped."))? } - ImageKind::SVG(ref svg) => svg.size, + ImageKind::RAW(width, height, _) => Size::from_wh(width as f32, height as f32) + .log_none(|| log::warn!("Image has an invalid size. Skipped."))?, + ImageKind::SVG(ref data) => { + let sub_opt = Options::default(); + + let tree = match Tree::from_data(data, &sub_opt) { + Ok(tree) => tree, + Err(_) => { + log::warn!("Failed to load subsvg image."); + return None; + } + }; + sanitize_sub_svg(&tree); + tree.size + } }; let rect = NonZeroRect::from_xywh( @@ -224,27 +250,27 @@ fn get_image_data_format(data: &[u8]) -> Option { /// /// Unlike `Tree::from_*` methods, this one will also remove all `image` elements /// from the loaded SVG, as required by the spec. -pub(crate) fn load_sub_svg(data: &[u8], opt: &Options) -> Option { - let mut sub_opt = Options::default(); - sub_opt.resources_dir = None; - sub_opt.dpi = opt.dpi; - sub_opt.font_size = opt.font_size; - sub_opt.languages = opt.languages.clone(); - sub_opt.shape_rendering = opt.shape_rendering; - sub_opt.text_rendering = opt.text_rendering; - sub_opt.image_rendering = opt.image_rendering; - sub_opt.default_size = opt.default_size; - - let tree = match Tree::from_data(data, &sub_opt) { - Ok(tree) => tree, - Err(_) => { - log::warn!("Failed to load subsvg image."); - return None; - } - }; - - sanitize_sub_svg(&tree); - Some(ImageKind::SVG(tree)) +pub(crate) fn load_sub_svg(data: &[u8], _: &Options) -> Option { + // let mut sub_opt = Options::default(); + // sub_opt.resources_dir = None; + // sub_opt.dpi = opt.dpi; + // sub_opt.font_size = opt.font_size; + // sub_opt.languages = opt.languages.clone(); + // sub_opt.shape_rendering = opt.shape_rendering; + // sub_opt.text_rendering = opt.text_rendering; + // sub_opt.image_rendering = opt.image_rendering; + // sub_opt.default_size = opt.default_size; + + // let tree = match Tree::from_data(data, &sub_opt) { + // Ok(tree) => tree, + // Err(_) => { + // log::warn!("Failed to load subsvg image."); + // return None; + // } + // }; + + // sanitize_sub_svg(&tree); + Some(ImageKind::SVG(Arc::new(data.to_vec()))) } // TODO: technically can simply override Options::image_href_resolver? diff --git a/crates/usvg-parser/src/marker.rs b/crates/usvg-parser/src/marker.rs index e7ff797c0..873946b03 100644 --- a/crates/usvg-parser/src/marker.rs +++ b/crates/usvg-parser/src/marker.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use strict_num::NonZeroPositiveF32; use svgtypes::Length; @@ -121,14 +121,14 @@ fn resolve( let mut clip_path = ClipPath::default(); clip_path.id = cache.gen_clip_path_id(); - let mut path = Path::new(Rc::new(tiny_skia_path::PathBuilder::from_rect( + let mut path = Path::new(Arc::new(tiny_skia_path::PathBuilder::from_rect( clip_rect.to_rect(), ))); path.fill = Some(usvg_tree::Fill::default()); clip_path.root.append_kind(NodeKind::Path(path)); - Some(Rc::new(clip_path)) + Some(Arc::new(clip_path)) } else { None }; diff --git a/crates/usvg-parser/src/mask.rs b/crates/usvg-parser/src/mask.rs index f944e0279..5bbda9790 100644 --- a/crates/usvg-parser/src/mask.rs +++ b/crates/usvg-parser/src/mask.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use svgtypes::{Length, LengthUnit as Unit}; use usvg_tree::{Group, Mask, MaskType, Node, NodeKind, NonZeroRect, Units}; @@ -14,7 +14,7 @@ pub(crate) fn convert( node: SvgNode, state: &converter::State, cache: &mut converter::Cache, -) -> Option> { +) -> Option> { // A `mask` attribute must reference a `mask` element. if node.tag_name() != Some(EId::Mask) { return None; @@ -72,7 +72,7 @@ pub(crate) fn convert( converter::convert_children(node, state, cache, &mut mask.root); if mask.root.has_children() { - let mask = Rc::new(mask); + let mask = Arc::new(mask); cache .masks .insert(node.element_id().to_string(), mask.clone()); diff --git a/crates/usvg-parser/src/options.rs b/crates/usvg-parser/src/options.rs index 5cfe1ec4b..0857b1173 100644 --- a/crates/usvg-parser/src/options.rs +++ b/crates/usvg-parser/src/options.rs @@ -7,7 +7,7 @@ use usvg_tree::{ImageRendering, ShapeRendering, Size, TextRendering}; use crate::ImageHrefResolver; /// Processing options. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Options { /// Directory that will be used during relative paths resolving. /// diff --git a/crates/usvg-parser/src/paint_server.rs b/crates/usvg-parser/src/paint_server.rs index c09411593..fd6e168f5 100644 --- a/crates/usvg-parser/src/paint_server.rs +++ b/crates/usvg-parser/src/paint_server.rs @@ -2,8 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; use std::str::FromStr; +use std::sync::Arc; use strict_num::PositiveF32; use svgtypes::{Length, LengthUnit as Unit}; @@ -77,7 +77,7 @@ fn convert_linear(node: SvgNode, state: &converter::State) -> Option Option SpreadMethod { diff --git a/crates/usvg-parser/src/shapes.rs b/crates/usvg-parser/src/shapes.rs index 42314e07a..bf46c6bd9 100644 --- a/crates/usvg-parser/src/shapes.rs +++ b/crates/usvg-parser/src/shapes.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use svgtypes::Length; use tiny_skia_path::Path; @@ -11,7 +11,7 @@ use usvg_tree::{tiny_skia_path, ApproxEqUlps, IsValidLength}; use crate::svgtree::{AId, EId, SvgNode}; use crate::{converter, units}; -pub(crate) fn convert(node: SvgNode, state: &converter::State) -> Option> { +pub(crate) fn convert(node: SvgNode, state: &converter::State) -> Option> { match node.tag_name()? { EId::Rect => convert_rect(node, state), EId::Circle => convert_circle(node, state), @@ -24,7 +24,7 @@ pub(crate) fn convert(node: SvgNode, state: &converter::State) -> Option Option> { +pub(crate) fn convert_path(node: SvgNode) -> Option> { let value: &str = node.attribute(AId::D)?; let mut builder = tiny_skia_path::PathBuilder::new(); for segment in svgtypes::SimplifyingPathParser::from(value) { @@ -61,10 +61,10 @@ pub(crate) fn convert_path(node: SvgNode) -> Option> { } } - builder.finish().map(Rc::new) + builder.finish().map(Arc::new) } -fn convert_rect(node: SvgNode, state: &converter::State) -> Option> { +fn convert_rect(node: SvgNode, state: &converter::State) -> Option> { // 'width' and 'height' attributes must be positive and non-zero. let width = node.convert_user_length(AId::Width, state, Length::zero()); let height = node.convert_user_length(AId::Height, state, Length::zero()); @@ -122,7 +122,7 @@ fn convert_rect(node: SvgNode, state: &converter::State) -> Option> { builder.finish()? }; - Some(Rc::new(path)) + Some(Arc::new(path)) } fn resolve_rx_ry(node: SvgNode, state: &converter::State) -> (f32, f32) { @@ -160,7 +160,7 @@ fn resolve_rx_ry(node: SvgNode, state: &converter::State) -> (f32, f32) { } } -fn convert_line(node: SvgNode, state: &converter::State) -> Option> { +fn convert_line(node: SvgNode, state: &converter::State) -> Option> { let x1 = node.convert_user_length(AId::X1, state, Length::zero()); let y1 = node.convert_user_length(AId::Y1, state, Length::zero()); let x2 = node.convert_user_length(AId::X2, state, Length::zero()); @@ -169,18 +169,18 @@ fn convert_line(node: SvgNode, state: &converter::State) -> Option> { let mut builder = tiny_skia_path::PathBuilder::new(); builder.move_to(x1, y1); builder.line_to(x2, y2); - builder.finish().map(Rc::new) + builder.finish().map(Arc::new) } -fn convert_polyline(node: SvgNode) -> Option> { +fn convert_polyline(node: SvgNode) -> Option> { let builder = points_to_path(node, "Polyline")?; - builder.finish().map(Rc::new) + builder.finish().map(Arc::new) } -fn convert_polygon(node: SvgNode) -> Option> { +fn convert_polygon(node: SvgNode) -> Option> { let mut builder = points_to_path(node, "Polygon")?; builder.close(); - builder.finish().map(Rc::new) + builder.finish().map(Arc::new) } fn points_to_path(node: SvgNode, eid: &str) -> Option { @@ -220,7 +220,7 @@ fn points_to_path(node: SvgNode, eid: &str) -> Option Option> { +fn convert_circle(node: SvgNode, state: &converter::State) -> Option> { let cx = node.convert_user_length(AId::Cx, state, Length::zero()); let cy = node.convert_user_length(AId::Cy, state, Length::zero()); let r = node.convert_user_length(AId::R, state, Length::zero()); @@ -236,7 +236,7 @@ fn convert_circle(node: SvgNode, state: &converter::State) -> Option> { ellipse_to_path(cx, cy, r, r) } -fn convert_ellipse(node: SvgNode, state: &converter::State) -> Option> { +fn convert_ellipse(node: SvgNode, state: &converter::State) -> Option> { let cx = node.convert_user_length(AId::Cx, state, Length::zero()); let cy = node.convert_user_length(AId::Cy, state, Length::zero()); let (rx, ry) = resolve_rx_ry(node, state); @@ -260,7 +260,7 @@ fn convert_ellipse(node: SvgNode, state: &converter::State) -> Option> ellipse_to_path(cx, cy, rx, ry) } -fn ellipse_to_path(cx: f32, cy: f32, rx: f32, ry: f32) -> Option> { +fn ellipse_to_path(cx: f32, cy: f32, rx: f32, ry: f32) -> Option> { let mut builder = tiny_skia_path::PathBuilder::new(); builder.move_to(cx + rx, cy); builder.arc_to(rx, ry, 0.0, false, true, cx, cy + ry); @@ -268,7 +268,7 @@ fn ellipse_to_path(cx: f32, cy: f32, rx: f32, ry: f32) -> Option> { builder.arc_to(rx, ry, 0.0, false, true, cx, cy - ry); builder.arc_to(rx, ry, 0.0, false, true, cx + rx, cy); builder.close(); - builder.finish().map(Rc::new) + builder.finish().map(Arc::new) } trait PathBuilderExt { diff --git a/crates/usvg-parser/src/text.rs b/crates/usvg-parser/src/text.rs index 4d195776e..0c00a793a 100644 --- a/crates/usvg-parser/src/text.rs +++ b/crates/usvg-parser/src/text.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use kurbo::{ParamCurve, ParamCurveArclen}; use svgtypes::{Length, LengthUnit}; @@ -341,7 +341,7 @@ fn resolve_text_flow(node: SvgNode, state: &converter::State) -> Option(AId::Transform) { let mut path_copy = path.as_ref().clone(); path_copy = path_copy.transform(node_transform)?; - Rc::new(path_copy) + Arc::new(path_copy) } else { path }; @@ -356,7 +356,7 @@ fn resolve_text_flow(node: SvgNode, state: &converter::State) -> Option Font { diff --git a/crates/usvg-parser/src/use_node.rs b/crates/usvg-parser/src/use_node.rs index b3bfab2ec..8cd1984e3 100644 --- a/crates/usvg-parser/src/use_node.rs +++ b/crates/usvg-parser/src/use_node.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use svgtypes::{Length, LengthUnit}; use usvg_tree::{ @@ -208,7 +208,7 @@ fn clip_element( let mut clip_path = usvg_tree::ClipPath::default(); clip_path.id = cache.gen_clip_path_id(); - let mut path = Path::new(Rc::new(tiny_skia_path::PathBuilder::from_rect( + let mut path = Path::new(Arc::new(tiny_skia_path::PathBuilder::from_rect( clip_rect.to_rect(), ))); path.fill = Some(usvg_tree::Fill::default()); @@ -224,7 +224,7 @@ fn clip_element( parent.append_kind(NodeKind::Group(Group { id, transform, - clip_path: Some(Rc::new(clip_path)), + clip_path: Some(Arc::new(clip_path)), ..Group::default() })) } diff --git a/crates/usvg-text-layout/src/lib.rs b/crates/usvg-text-layout/src/lib.rs index b0dd175be..99e2362c4 100644 --- a/crates/usvg-text-layout/src/lib.rs +++ b/crates/usvg-text-layout/src/lib.rs @@ -23,10 +23,9 @@ An [SVG] text layout implementation on top of [usvg] crate. pub use fontdb; -use std::collections::HashMap; use std::convert::TryFrom; use std::num::NonZeroU16; -use std::rc::Rc; +use std::{collections::HashMap, sync::Arc}; use fontdb::{Database, ID}; use kurbo::{ParamCurve, ParamCurveArclen, ParamCurveDeriv}; @@ -453,7 +452,7 @@ fn resolve_baseline(span: &TextSpan, font: &ResolvedFont, writing_mode: WritingM shift } -type FontsCache = HashMap>; +type FontsCache = HashMap>; fn text_to_paths( text_node: &Text, @@ -465,7 +464,7 @@ fn text_to_paths( for span in &chunk.spans { if !fonts_cache.contains_key(&span.font) { if let Some(font) = resolve_font(&span.font, fontdb) { - fonts_cache.insert(span.font.clone(), Rc::new(font)); + fonts_cache.insert(span.font.clone(), Arc::new(font)); } } } @@ -714,7 +713,7 @@ fn convert_span( paint_order: span.paint_order, rendering_mode: ShapeRendering::default(), text_bbox: Some(bboxes.bounds().to_non_zero_rect()?), - data: Rc::new(path), + data: Arc::new(path), }; Some(path) @@ -789,7 +788,7 @@ fn convert_decoration( let mut path_data = builder.finish()?; path_data = path_data.transform(transform)?; - let mut path = Path::new(Rc::new(path_data)); + let mut path = Path::new(Arc::new(path_data)); path.visibility = span.visibility; path.fill = decoration.fill.take(); path.stroke = decoration.stroke.take(); @@ -833,7 +832,7 @@ fn paint_server_to_user_space_on_use(paint: Paint, bbox: Rect) -> Option Paint::Color(_) => paint, Paint::LinearGradient(ref lg) => { let transform = lg.transform.post_concat(ts); - Paint::LinearGradient(Rc::new(LinearGradient { + Paint::LinearGradient(Arc::new(LinearGradient { id: String::new(), x1: lg.x1, y1: lg.y1, @@ -849,7 +848,7 @@ fn paint_server_to_user_space_on_use(paint: Paint, bbox: Rect) -> Option } Paint::RadialGradient(ref rg) => { let transform = rg.transform.post_concat(ts); - Paint::RadialGradient(Rc::new(RadialGradient { + Paint::RadialGradient(Arc::new(RadialGradient { id: String::new(), cx: rg.cx, cy: rg.cy, @@ -866,7 +865,7 @@ fn paint_server_to_user_space_on_use(paint: Paint, bbox: Rect) -> Option } Paint::Pattern(ref patt) => { let transform = patt.transform.post_concat(ts); - Paint::Pattern(Rc::new(Pattern { + Paint::Pattern(Arc::new(Pattern { id: String::new(), units: Units::UserSpaceOnUse, content_units: patt.content_units, @@ -916,7 +915,7 @@ struct Glyph { /// Reference to the source font. /// /// Each glyph can have it's own source font. - font: Rc, + font: Arc, } impl Glyph { @@ -1090,7 +1089,7 @@ fn outline_chunk( /// Text shaping with font fallback. fn shape_text( text: &str, - font: Rc, + font: Arc, small_caps: bool, apply_kerning: bool, fontdb: &fontdb::Database, @@ -1113,7 +1112,7 @@ fn shape_text( if let Some(c) = missing { let fallback_font = match find_font_for_char(c, &used_fonts, fontdb) { - Some(v) => Rc::new(v), + Some(v) => Arc::new(v), None => break 'outer, }; @@ -1177,7 +1176,7 @@ fn shape_text( /// This function will do the BIDI reordering and text shaping. fn shape_text_with_font( text: &str, - font: Rc, + font: Arc, small_caps: bool, apply_kerning: bool, fontdb: &fontdb::Database, diff --git a/crates/usvg-tree/src/lib.rs b/crates/usvg-tree/src/lib.rs index 93dd0013c..0fe49948f 100644 --- a/crates/usvg-tree/src/lib.rs +++ b/crates/usvg-tree/src/lib.rs @@ -22,7 +22,6 @@ pub mod filter; mod geom; mod text; -use std::rc::Rc; use std::sync::Arc; pub use strict_num::{self, ApproxEqUlps, NonZeroPositiveF32, NormalizedF32, PositiveF32}; @@ -577,9 +576,9 @@ impl Color { #[derive(Clone, Debug)] pub enum Paint { Color(Color), - LinearGradient(Rc), - RadialGradient(Rc), - Pattern(Rc), + LinearGradient(Arc), + RadialGradient(Arc), + Pattern(Arc), } impl Paint { @@ -602,9 +601,9 @@ impl PartialEq for Paint { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Color(lc), Self::Color(rc)) => lc == rc, - (Self::LinearGradient(ref lg1), Self::LinearGradient(ref lg2)) => Rc::ptr_eq(lg1, lg2), - (Self::RadialGradient(ref rg1), Self::RadialGradient(ref rg2)) => Rc::ptr_eq(rg1, rg2), - (Self::Pattern(ref p1), Self::Pattern(ref p2)) => Rc::ptr_eq(p1, p2), + (Self::LinearGradient(ref lg1), Self::LinearGradient(ref lg2)) => Arc::ptr_eq(lg1, lg2), + (Self::RadialGradient(ref rg1), Self::RadialGradient(ref rg2)) => Arc::ptr_eq(rg1, rg2), + (Self::Pattern(ref p1), Self::Pattern(ref p2)) => Arc::ptr_eq(p1, p2), _ => false, } } @@ -634,7 +633,7 @@ pub struct ClipPath { /// Additional clip path. /// /// `clip-path` in SVG. - pub clip_path: Option>, + pub clip_path: Option>, /// Clip path children. /// @@ -703,7 +702,7 @@ pub struct Mask { /// Additional mask. /// /// `mask` in SVG. - pub mask: Option>, + pub mask: Option>, /// Clip path children. /// @@ -778,13 +777,13 @@ pub struct Group { pub isolate: bool, /// Element's clip path. - pub clip_path: Option>, + pub clip_path: Option>, /// Element's mask. - pub mask: Option>, + pub mask: Option>, /// Element's filters. - pub filters: Vec>, + pub filters: Vec>, } impl Default for Group { @@ -883,12 +882,12 @@ pub struct Path { /// Segments list. /// /// All segments are in absolute coordinates. - pub data: Rc, + pub data: Arc, } impl Path { /// Creates a new `Path` with default values. - pub fn new(data: Rc) -> Self { + pub fn new(data: Arc) -> Self { Path { id: String::new(), transform: Transform::default(), @@ -913,7 +912,9 @@ pub enum ImageKind { /// A reference to raw GIF data. Should be decoded by the caller. GIF(Arc>), /// A preprocessed SVG tree. Can be rendered as is. - SVG(Tree), + SVG(Arc>), + /// RAW image data + RAW(u32, u32, Arc>) } impl std::fmt::Debug for ImageKind { @@ -923,6 +924,7 @@ impl std::fmt::Debug for ImageKind { ImageKind::PNG(_) => f.write_str("ImageKind::PNG(..)"), ImageKind::GIF(_) => f.write_str("ImageKind::GIF(..)"), ImageKind::SVG(_) => f.write_str("ImageKind::SVG(..)"), + ImageKind::RAW(_, _, _) => f.write_str("ImageKind::RAW(..)"), } } } @@ -1017,21 +1019,21 @@ impl Tree { /// Calls a closure for each [`ClipPath`] in the tree. /// /// Doesn't guarantee to have unique clip paths. A caller must deduplicate them manually. - pub fn clip_paths)>(&self, mut f: F) { + pub fn clip_paths)>(&self, mut f: F) { loop_over_clip_paths(&self.root, &mut f) } /// Calls a closure for each [`Mask`] in the tree. /// /// Doesn't guarantee to have unique masks. A caller must deduplicate them manually. - pub fn masks)>(&self, mut f: F) { + pub fn masks)>(&self, mut f: F) { loop_over_masks(&self.root, &mut f) } /// Calls a closure for each [`Filter`](filter::Filter) in the tree. /// /// Doesn't guarantee to have unique filters. A caller must deduplicate them manually. - pub fn filters)>(&self, mut f: F) { + pub fn filters)>(&self, mut f: F) { loop_over_filters(&self.root, &mut f) } } @@ -1096,7 +1098,7 @@ fn loop_over_paint_servers(root: &Node, f: &mut dyn FnMut(&Paint)) { } } -fn loop_over_clip_paths(root: &Node, f: &mut dyn FnMut(Rc)) { +fn loop_over_clip_paths(root: &Node, f: &mut dyn FnMut(Arc)) { for node in root.descendants() { if let NodeKind::Group(ref g) = *node.borrow() { if let Some(ref clip) = g.clip_path { @@ -1112,7 +1114,7 @@ fn loop_over_clip_paths(root: &Node, f: &mut dyn FnMut(Rc)) { } } -fn loop_over_masks(root: &Node, f: &mut dyn FnMut(Rc)) { +fn loop_over_masks(root: &Node, f: &mut dyn FnMut(Arc)) { for node in root.descendants() { if let NodeKind::Group(ref g) = *node.borrow() { if let Some(ref mask) = g.mask { @@ -1128,7 +1130,7 @@ fn loop_over_masks(root: &Node, f: &mut dyn FnMut(Rc)) { } } -fn loop_over_filters(root: &Node, f: &mut dyn FnMut(Rc)) { +fn loop_over_filters(root: &Node, f: &mut dyn FnMut(Arc)) { for node in root.descendants() { if let NodeKind::Group(ref g) = *node.borrow() { for filter in &g.filters { diff --git a/crates/usvg-tree/src/text.rs b/crates/usvg-tree/src/text.rs index 44fb3e019..a26b6c681 100644 --- a/crates/usvg-tree/src/text.rs +++ b/crates/usvg-tree/src/text.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use std::rc::Rc; +use std::sync::Arc; use strict_num::NonZeroPositiveF32; @@ -244,7 +244,7 @@ pub struct TextPath { pub start_offset: f32, /// A path. - pub path: Rc, + pub path: Arc, } /// A text chunk flow property. @@ -255,7 +255,7 @@ pub enum TextFlow { /// Includes left-to-right, right-to-left and top-to-bottom. Linear, /// A text-on-path layout. - Path(Rc), + Path(Arc), } /// A text chunk. diff --git a/crates/usvg/src/lib.rs b/crates/usvg/src/lib.rs index 79bfb5299..f9f9bcd02 100644 --- a/crates/usvg/src/lib.rs +++ b/crates/usvg/src/lib.rs @@ -48,7 +48,7 @@ and can focus just on the rendering part. */ #![forbid(unsafe_code)] -#![warn(missing_docs)] +// #![warn(missing_docs)] #![warn(missing_debug_implementations)] #![warn(missing_copy_implementations)] diff --git a/crates/usvg/src/writer.rs b/crates/usvg/src/writer.rs index cccde57d0..33ef5eb16 100644 --- a/crates/usvg/src/writer.rs +++ b/crates/usvg/src/writer.rs @@ -4,7 +4,7 @@ use std::fmt::Display; use std::io::Write; -use std::rc::Rc; +use std::sync::Arc; use crate::TreeWriting; use usvg_parser::{AId, EId}; @@ -83,7 +83,7 @@ pub(crate) fn convert(tree: &Tree, opt: &XmlOptions) -> String { fn conv_filters(tree: &Tree, opt: &XmlOptions, xml: &mut XmlWriter) { let mut filters = Vec::new(); tree.filters(|filter| { - if !filters.iter().any(|other| Rc::ptr_eq(&filter, other)) { + if !filters.iter().any(|other| Arc::ptr_eq(&filter, other)) { filters.push(filter); } }); @@ -505,7 +505,7 @@ fn conv_defs(tree: &Tree, opt: &XmlOptions, xml: &mut XmlWriter) { let mut clip_paths = Vec::new(); tree.clip_paths(|clip| { - if !clip_paths.iter().any(|other| Rc::ptr_eq(&clip, other)) { + if !clip_paths.iter().any(|other| Arc::ptr_eq(&clip, other)) { clip_paths.push(clip); } }); @@ -526,7 +526,7 @@ fn conv_defs(tree: &Tree, opt: &XmlOptions, xml: &mut XmlWriter) { let mut masks = Vec::new(); tree.masks(|mask| { - if !masks.iter().any(|other| Rc::ptr_eq(&mask, other)) { + if !masks.iter().any(|other| Arc::ptr_eq(&mask, other)) { masks.push(mask); } }); @@ -910,14 +910,17 @@ impl XmlWriterExt for XmlWriter { } fn write_image_data(&mut self, kind: &usvg_tree::ImageKind) { - let svg_string; + let mut buf = vec![]; let (mime, data) = match kind { usvg_tree::ImageKind::JPEG(ref data) => ("jpeg", data.as_slice()), usvg_tree::ImageKind::PNG(ref data) => ("png", data.as_slice()), usvg_tree::ImageKind::GIF(ref data) => ("gif", data.as_slice()), - usvg_tree::ImageKind::SVG(ref tree) => { - svg_string = tree.to_string(&XmlOptions::default()); - ("svg+xml", svg_string.as_bytes()) + usvg_tree::ImageKind::SVG(ref tree) => ("svg+xml", tree.as_slice()), + usvg_tree::ImageKind::RAW(w, h, data) => { + buf.extend_from_slice(&w.to_be_bytes()); + buf.extend_from_slice(&h.to_be_bytes()); + buf.extend_from_slice(&data.as_slice()); + ("raw", buf.as_slice()) } };