{
- match marker_node.attribute(AId::MarkerUnits) {
- Some("userSpaceOnUse") => NonZeroPositiveF32::new(1.0),
- _ => path_node.resolve_valid_length(AId::StrokeWidth, state, 1.0),
- }
-}
-
-fn draw_markers(path: &[Segment], kind: MarkerKind, mut draw_marker: P)
-where
- P: FnMut(tiny_skia_path::Point, usize),
-{
- match kind {
- MarkerKind::Start => {
- if let Some(Segment::MoveTo(p)) = path.first().cloned() {
- draw_marker(p, 0);
- }
- }
- MarkerKind::Middle => {
- let total = path.len() - 1;
- let mut i = 1;
- while i < total {
- let p = match path[i] {
- Segment::MoveTo(p) => p,
- Segment::LineTo(p) => p,
- Segment::CubicTo(_, _, p) => p,
- _ => {
- i += 1;
- continue;
- }
- };
-
- draw_marker(p, i);
-
- i += 1;
- }
- }
- MarkerKind::End => {
- let idx = path.len() - 1;
- match path.last().cloned() {
- Some(Segment::LineTo(p)) => {
- draw_marker(p, idx);
- }
- Some(Segment::CubicTo(_, _, p)) => {
- draw_marker(p, idx);
- }
- Some(Segment::Close) => {
- let p = get_subpath_start(path, idx);
- draw_marker(p, idx);
- }
- _ => {}
- }
- }
- }
-}
-
-fn calc_vertex_angle(path: &[Segment], idx: usize) -> f32 {
- if idx == 0 {
- // First segment.
-
- debug_assert!(path.len() > 1);
-
- let seg1 = path[0];
- let seg2 = path[1];
-
- match (seg1, seg2) {
- (Segment::MoveTo(pm), Segment::LineTo(p)) => calc_line_angle(pm.x, pm.y, p.x, p.y),
- (Segment::MoveTo(pm), Segment::CubicTo(p1, _, p)) => {
- if pm.x.approx_eq_ulps(&p1.x, 4) && pm.y.approx_eq_ulps(&p1.y, 4) {
- calc_line_angle(pm.x, pm.y, p.x, p.y)
- } else {
- calc_line_angle(pm.x, pm.y, p1.x, p1.y)
- }
- }
- _ => 0.0,
- }
- } else if idx == path.len() - 1 {
- // Last segment.
-
- let seg1 = path[idx - 1];
- let seg2 = path[idx];
-
- match (seg1, seg2) {
- (_, Segment::MoveTo(_)) => 0.0, // unreachable
- (_, Segment::LineTo(p)) => {
- let prev = get_prev_vertex(path, idx);
- calc_line_angle(prev.x, prev.y, p.x, p.y)
- }
- (_, Segment::CubicTo(p1, p2, p)) => {
- if p2.x.approx_eq_ulps(&p.x, 4) && p2.y.approx_eq_ulps(&p.y, 4) {
- calc_line_angle(p1.x, p1.y, p.x, p.y)
- } else {
- calc_line_angle(p2.x, p2.y, p.x, p.y)
- }
- }
- (Segment::LineTo(p), Segment::Close) => {
- let next = get_subpath_start(path, idx);
- calc_line_angle(p.x, p.y, next.x, next.y)
- }
- (Segment::CubicTo(_, p2, p), Segment::Close) => {
- let prev = get_prev_vertex(path, idx);
- let next = get_subpath_start(path, idx);
- calc_curves_angle(
- prev.x, prev.y, p2.x, p2.y, p.x, p.y, next.x, next.y, next.x, next.y,
- )
- }
- (_, Segment::Close) => 0.0,
- }
- } else {
- // Middle segments.
-
- let seg1 = path[idx];
- let seg2 = path[idx + 1];
-
- // TODO: Not sure if there is a better way.
- match (seg1, seg2) {
- (Segment::MoveTo(pm), Segment::LineTo(p)) => calc_line_angle(pm.x, pm.y, p.x, p.y),
- (Segment::MoveTo(pm), Segment::CubicTo(p1, _, _)) => {
- calc_line_angle(pm.x, pm.y, p1.x, p1.y)
- }
- (Segment::LineTo(p1), Segment::LineTo(p2)) => {
- let prev = get_prev_vertex(path, idx);
- calc_angle(prev.x, prev.y, p1.x, p1.y, p1.x, p1.y, p2.x, p2.y)
- }
- (Segment::CubicTo(_, c1_p2, c1_p), Segment::CubicTo(c2_p1, _, c2_p)) => {
- let prev = get_prev_vertex(path, idx);
- calc_curves_angle(
- prev.x, prev.y, c1_p2.x, c1_p2.y, c1_p.x, c1_p.y, c2_p1.x, c2_p1.y, c2_p.x,
- c2_p.y,
- )
- }
- (Segment::LineTo(pl), Segment::CubicTo(p1, _, p)) => {
- let prev = get_prev_vertex(path, idx);
- calc_curves_angle(
- prev.x, prev.y, prev.x, prev.y, pl.x, pl.y, p1.x, p1.y, p.x, p.y,
- )
- }
- (Segment::CubicTo(_, p2, p), Segment::LineTo(pl)) => {
- let prev = get_prev_vertex(path, idx);
- calc_curves_angle(prev.x, prev.y, p2.x, p2.y, p.x, p.y, pl.x, pl.y, pl.x, pl.y)
- }
- (Segment::LineTo(p), Segment::MoveTo(_)) => {
- let prev = get_prev_vertex(path, idx);
- calc_line_angle(prev.x, prev.y, p.x, p.y)
- }
- (Segment::CubicTo(_, p2, p), Segment::MoveTo(_)) => {
- if p.x.approx_eq_ulps(&p2.x, 4) && p.y.approx_eq_ulps(&p2.y, 4) {
- let prev = get_prev_vertex(path, idx);
- calc_line_angle(prev.x, prev.y, p.x, p.y)
- } else {
- calc_line_angle(p2.x, p2.y, p.x, p.y)
- }
- }
- (Segment::LineTo(p), Segment::Close) => {
- let prev = get_prev_vertex(path, idx);
- let next = get_subpath_start(path, idx);
- calc_angle(prev.x, prev.y, p.x, p.y, p.x, p.y, next.x, next.y)
- }
- (_, Segment::Close) => {
- let prev = get_prev_vertex(path, idx);
- let next = get_subpath_start(path, idx);
- calc_line_angle(prev.x, prev.y, next.x, next.y)
- }
- (_, Segment::MoveTo(_)) | (Segment::Close, _) => 0.0,
- }
- }
-}
-
-fn calc_line_angle(x1: f32, y1: f32, x2: f32, y2: f32) -> f32 {
- calc_angle(x1, y1, x2, y2, x1, y1, x2, y2)
-}
-
-fn calc_curves_angle(
- px: f32,
- py: f32, // previous vertex
- cx1: f32,
- cy1: f32, // previous control point
- x: f32,
- y: f32, // current vertex
- cx2: f32,
- cy2: f32, // next control point
- nx: f32,
- ny: f32, // next vertex
-) -> f32 {
- if cx1.approx_eq_ulps(&x, 4) && cy1.approx_eq_ulps(&y, 4) {
- calc_angle(px, py, x, y, x, y, cx2, cy2)
- } else if x.approx_eq_ulps(&cx2, 4) && y.approx_eq_ulps(&cy2, 4) {
- calc_angle(cx1, cy1, x, y, x, y, nx, ny)
- } else {
- calc_angle(cx1, cy1, x, y, x, y, cx2, cy2)
- }
-}
-
-fn calc_angle(x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32, x4: f32, y4: f32) -> f32 {
- use std::f32::consts::*;
-
- fn normalize(rad: f32) -> f32 {
- let v = rad % (PI * 2.0);
- if v < 0.0 {
- v + PI * 2.0
- } else {
- v
- }
- }
-
- fn vector_angle(vx: f32, vy: f32) -> f32 {
- let rad = vy.atan2(vx);
- if rad.is_nan() {
- 0.0
- } else {
- normalize(rad)
- }
- }
-
- let in_a = vector_angle(x2 - x1, y2 - y1);
- let out_a = vector_angle(x4 - x3, y4 - y3);
- let d = (out_a - in_a) * 0.5;
-
- let mut angle = in_a + d;
- if FRAC_PI_2 < d.abs() {
- angle -= PI;
- }
-
- normalize(angle).to_degrees()
-}
-
-fn get_subpath_start(segments: &[Segment], idx: usize) -> tiny_skia_path::Point {
- let offset = segments.len() - idx;
- for seg in segments.iter().rev().skip(offset) {
- if let Segment::MoveTo(p) = *seg {
- return p;
- }
- }
-
- tiny_skia_path::Point::zero()
-}
-
-fn get_prev_vertex(segments: &[Segment], idx: usize) -> tiny_skia_path::Point {
- match segments[idx - 1] {
- Segment::MoveTo(p) => p,
- Segment::LineTo(p) => p,
- Segment::CubicTo(_, _, p) => p,
- Segment::Close => get_subpath_start(segments, idx),
- }
-}
-
-fn convert_rect(node: SvgNode, state: &converter::State) -> Option {
- NonZeroRect::from_xywh(
- node.convert_user_length(AId::RefX, state, Length::zero()),
- node.convert_user_length(AId::RefY, state, Length::zero()),
- node.convert_user_length(AId::MarkerWidth, state, Length::new_number(3.0)),
- node.convert_user_length(AId::MarkerHeight, state, Length::new_number(3.0)),
- )
-}
-
-fn convert_orientation(node: SvgNode) -> MarkerOrientation {
- match node.attribute(AId::Orient) {
- Some("auto") => MarkerOrientation::Auto,
- Some("auto-start-reverse") => MarkerOrientation::AutoStartReverse,
- _ => match node.attribute::(AId::Orient) {
- Some(angle) => MarkerOrientation::Angle(angle.to_degrees() as f32),
- None => MarkerOrientation::Angle(0.0),
- },
- }
-}
-
-fn quad_to_curve(prev: Point, p1: Point, p: Point) -> (Point, Point, Point) {
- #[inline]
- fn calc(n1: f32, n2: f32) -> f32 {
- (n1 + n2 * 2.0) / 3.0
- }
-
- (
- Point::from_xy(calc(prev.x, p1.x), calc(prev.y, p1.y)),
- Point::from_xy(calc(p.x, p1.x), calc(p.y, p1.y)),
- p,
- )
-}
diff --git a/resvg-0.43.0/crates/usvg/src/parser/mask.rs b/resvg-0.43.0/crates/usvg/src/parser/mask.rs
deleted file mode 100644
index cdc88e9..0000000
--- a/resvg-0.43.0/crates/usvg/src/parser/mask.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-// This Source Code Form is subject to the terms of the Mozilla Public
-// 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::sync::Arc;
-
-use svgtypes::{Length, LengthUnit as Unit};
-
-use super::svgtree::{AId, EId, SvgNode};
-use super::{converter, OptionLog};
-use crate::{Group, Mask, MaskType, Node, NonEmptyString, NonZeroRect, Transform, Units};
-
-pub(crate) fn convert(
- node: SvgNode,
- state: &converter::State,
- object_bbox: Option,
- cache: &mut converter::Cache,
-) -> Option> {
- // A `mask` attribute must reference a `mask` element.
- if node.tag_name() != Some(EId::Mask) {
- return None;
- }
-
- let units = node
- .attribute(AId::MaskUnits)
- .unwrap_or(Units::ObjectBoundingBox);
-
- let content_units = node
- .attribute(AId::MaskContentUnits)
- .unwrap_or(Units::UserSpaceOnUse);
-
- // Check if this element was already converted.
- //
- // Only `userSpaceOnUse` masks can be shared,
- // because `objectBoundingBox` one will be converted into user one
- // and will become node-specific.
- let cacheable = units == Units::UserSpaceOnUse && content_units == Units::UserSpaceOnUse;
- if cacheable {
- if let Some(mask) = cache.masks.get(node.element_id()) {
- return Some(mask.clone());
- }
- }
-
- let rect = NonZeroRect::from_xywh(
- node.convert_length(AId::X, units, state, Length::new(-10.0, Unit::Percent)),
- node.convert_length(AId::Y, units, state, Length::new(-10.0, Unit::Percent)),
- node.convert_length(AId::Width, units, state, Length::new(120.0, Unit::Percent)),
- node.convert_length(AId::Height, units, state, Length::new(120.0, Unit::Percent)),
- );
- let mut rect =
- rect.log_none(|| log::warn!("Mask '{}' has an invalid size. Skipped.", node.element_id()))?;
-
- let mut mask_all = false;
- if units == Units::ObjectBoundingBox {
- if let Some(bbox) = object_bbox {
- rect = rect.bbox_transform(bbox)
- } else {
- // When mask units are `objectBoundingBox` and bbox is zero-sized - the whole
- // element should be masked.
- // Technically an UB, but this is what Chrome and Firefox do.
- mask_all = true;
- }
- }
-
- let mut id = NonEmptyString::new(node.element_id().to_string())?;
- // Generate ID only when we're parsing `objectBoundingBox` mask for the second time.
- if !cacheable && cache.masks.contains_key(id.get()) {
- id = cache.gen_mask_id();
- }
- let id_copy = id.get().to_string();
-
- if mask_all {
- let mask = Arc::new(Mask {
- id,
- rect,
- kind: MaskType::Luminance,
- mask: None,
- root: Group::empty(),
- });
- cache.masks.insert(id_copy, mask.clone());
- return Some(mask);
- }
-
- // Resolve linked mask.
- let mut mask = None;
- if let Some(link) = node.attribute::(AId::Mask) {
- mask = convert(link, state, object_bbox, cache);
-
- // Linked `mask` must be valid.
- if mask.is_none() {
- return None;
- }
- }
-
- let kind = if node.attribute(AId::MaskType) == Some("alpha") {
- MaskType::Alpha
- } else {
- MaskType::Luminance
- };
-
- let mut mask = Mask {
- id,
- rect,
- kind,
- mask,
- root: Group::empty(),
- };
-
- // To emulate content `objectBoundingBox` units we have to put
- // mask children into a group with a transform.
- let mut subroot = None;
- if content_units == Units::ObjectBoundingBox {
- let object_bbox = match object_bbox {
- Some(v) => v,
- None => {
- log::warn!("Masking of zero-sized shapes is not allowed.");
- return None;
- }
- };
-
- let mut g = Group::empty();
- g.transform = Transform::from_bbox(object_bbox);
- // Make sure to set `abs_transform`, because it must propagate to all children.
- g.abs_transform = g.transform;
-
- subroot = Some(g);
- }
-
- {
- // Prefer `subroot` to `mask.root`.
- let real_root = subroot.as_mut().unwrap_or(&mut mask.root);
- converter::convert_children(node, state, cache, real_root);
-
- // A mask without children at this point is invalid.
- // Only masks with zero bbox and `objectBoundingBox` can be empty.
- if !real_root.has_children() {
- return None;
- }
- }
-
- if let Some(mut subroot) = subroot {
- subroot.calculate_bounding_boxes();
- mask.root.children.push(Node::Group(Box::new(subroot)));
- }
-
- mask.root.calculate_bounding_boxes();
-
- let mask = Arc::new(mask);
- cache.masks.insert(id_copy, mask.clone());
- Some(mask)
-}
diff --git a/resvg-0.43.0/crates/usvg/src/parser/mod.rs b/resvg-0.43.0/crates/usvg/src/parser/mod.rs
deleted file mode 100644
index 1f52c3b..0000000
--- a/resvg-0.43.0/crates/usvg/src/parser/mod.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-// This Source Code Form is subject to the terms of the Mozilla Public
-// 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/.
-
-mod clippath;
-mod converter;
-mod filter;
-mod image;
-mod marker;
-mod mask;
-mod options;
-mod paint_server;
-mod shapes;
-mod style;
-mod svgtree;
-mod switch;
-mod units;
-mod use_node;
-
-#[cfg(feature = "text")]
-mod text;
-
-pub use image::{ImageHrefDataResolverFn, ImageHrefResolver, ImageHrefStringResolverFn};
-pub use options::Options;
-pub(crate) use svgtree::{AId, EId};
-
-/// List of all errors.
-#[derive(Debug)]
-pub enum Error {
- /// Only UTF-8 content are supported.
- NotAnUtf8Str,
-
- /// Compressed SVG must use the GZip algorithm.
- MalformedGZip,
-
- /// We do not allow SVG with more than 1_000_000 elements for security reasons.
- ElementsLimitReached,
-
- /// SVG doesn't have a valid size.
- ///
- /// Occurs when width and/or height are <= 0.
- ///
- /// Also occurs if width, height and viewBox are not set.
- InvalidSize,
-
- /// Failed to parse an SVG data.
- ParsingFailed(roxmltree::Error),
-}
-
-impl From for Error {
- fn from(e: roxmltree::Error) -> Self {
- Error::ParsingFailed(e)
- }
-}
-
-impl std::fmt::Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match *self {
- Error::NotAnUtf8Str => {
- write!(f, "provided data has not an UTF-8 encoding")
- }
- Error::MalformedGZip => {
- write!(f, "provided data has a malformed GZip content")
- }
- Error::ElementsLimitReached => {
- write!(f, "the maximum number of SVG elements has been reached")
- }
- Error::InvalidSize => {
- write!(f, "SVG has an invalid size")
- }
- Error::ParsingFailed(ref e) => {
- write!(f, "SVG data parsing failed cause {}", e)
- }
- }
- }
-}
-
-impl std::error::Error for Error {}
-
-pub(crate) trait OptionLog {
- fn log_none