use tiny_skia::Transform;
pub(crate) fn merge_transformed(
paths: &[tiny_skia::Path],
transform: Transform,
) -> Option<tiny_skia::Path> {
let mut builder = tiny_skia::PathBuilder::new();
for path in paths {
if let Some(transformed) = path.clone().transform(transform) {
builder.push_path(&transformed);
}
}
builder.finish()
}
#[cfg(not(feature = "nostd"))]
pub(crate) fn stroke_outline(path: &tiny_skia::Path, wx: f32, wy: f32) -> Option<tiny_skia::Path> {
let mk = |w: f32| tiny_skia::Stroke {
width: w * 2.0,
line_cap: tiny_skia::LineCap::Square,
line_join: tiny_skia::LineJoin::Miter,
..Default::default()
};
let mut stroker = tiny_skia::PathStroker::new();
if (wx - wy).abs() < 0.05 || wx <= 0.0 || wy <= 0.0 {
return stroker.stroke(path, &mk(wx.max(wy)), 1.0);
}
let sy = wx / wy;
let scaled = path.clone().transform(Transform::from_scale(1.0, sy))?;
let stroked = stroker.stroke(&scaled, &mk(wx), 1.0)?;
stroked.transform(Transform::from_scale(1.0, 1.0 / sy))
}
#[cfg(not(feature = "nostd"))]
pub(crate) fn project_path_3d(
path: &tiny_skia::Path,
frx_rad: f32,
fry_rad: f32,
cx: f32,
cy: f32,
dist: f32,
) -> Option<tiny_skia::Path> {
use tiny_skia::{PathSegment, Point};
let (sfx, cfx) = (-frx_rad.sin(), frx_rad.cos());
let (sfy, cfy) = (fry_rad.sin(), fry_rad.cos());
let project = |p: Point| -> Point {
let dx = p.x - cx;
let dy = p.y - cy;
let z3 = dy * sfx; let y3 = dy * cfx; let x4 = dx * cfy - z3 * sfy;
let z4 = dx * sfy + z3 * cfy;
let zf = (z4 + dist).max(0.1);
Point::from_xy(cx + x4 * dist / zf, cy + y3 * dist / zf)
};
let mut pb = tiny_skia::PathBuilder::new();
for seg in path.segments() {
match seg {
PathSegment::MoveTo(p) => {
let q = project(p);
pb.move_to(q.x, q.y);
}
PathSegment::LineTo(p) => {
let q = project(p);
pb.line_to(q.x, q.y);
}
PathSegment::QuadTo(a, b) => {
let (qa, qb) = (project(a), project(b));
pb.quad_to(qa.x, qa.y, qb.x, qb.y);
}
PathSegment::CubicTo(a, b, c) => {
let (qa, qb, qc) = (project(a), project(b), project(c));
pb.cubic_to(qa.x, qa.y, qb.x, qb.y, qc.x, qc.y);
}
PathSegment::Close => pb.close(),
}
}
pb.finish()
}
#[cfg(not(feature = "nostd"))]
pub(crate) fn shadow_delta(local: Transform, sx: f32, sy: f32) -> (i32, i32) {
(
(sx * local.sx + sy * local.kx).round() as i32,
(sx * local.ky + sy * local.sy).round() as i32,
)
}