///|
/// `Cmd` represents an SVG command along with its parameters.
struct Cmd {
c : String
p : Params
} derive(Debug, Eq)
///|
pub impl Show for Cmd with fn output(self, logger) {
let { c, p } = self
logger.write_string(
(
$|{c: \{c.escape(quote=true)}, p: \{p}}
),
)
}
///|
test "Cmd show interface" {
let cmd = { c: "M", p: Params([10.0, 20.0]) }
inspect(
cmd,
content=(
#|{c: "M", p: Params([10, 20])}
),
)
}
///|
let split_re : @regexp.Regexp = try! @regexp.compile(
"^([MLCQZ])([0-9\\.\\-,\\s]*)",
flags="m",
)
///|
/// `split_path` splits an SVG path into an array of individual commands.
fn split_path(d : String) -> Array[Cmd] raise FontError {
let mut d = d
let cmds = []
while d.length() > 0 {
let match_result = split_re
.match_(d)
.unwrap_or_error(
FontError("split_path: unable to parse SVG params: \{d}"),
)
match match_result.results() {
[_, Some(c), Some(p)] => {
d = d.unsafe_substring(start=c.length() + p.length(), end=d.length())
let c = c.to_owned()
let p = parse_params(p.to_owned())
cmds.push({ c, p })
}
_ => raise FontError("split_path: unable to split SVG path \{d}")
}
}
cmds
}
///|
test "split_path" {
let d =
#|M507 24L48 24L48 530L395 530L395 625L48 625L48 723L507
#|723L507 24ZM395 269L395 433L138 433L138 269L395 269Z
let got = split_path(d)
let want = [
{ c: "M", p: Params([507.0, 24.0]) },
{ c: "L", p: Params([48.0, 24.0]) },
{ c: "L", p: Params([48.0, 530.0]) },
{ c: "L", p: Params([395.0, 530.0]) },
{ c: "L", p: Params([395.0, 625.0]) },
{ c: "L", p: Params([48.0, 625.0]) },
{ c: "L", p: Params([48.0, 723.0]) },
{ c: "L", p: Params([507.0, 723.0]) },
{ c: "L", p: Params([507.0, 24.0]) },
{ c: "Z", p: Params([]) },
{ c: "M", p: Params([395.0, 269.0]) },
{ c: "L", p: Params([395.0, 433.0]) },
{ c: "L", p: Params([138.0, 433.0]) },
{ c: "L", p: Params([138.0, 269.0]) },
{ c: "L", p: Params([395.0, 269.0]) },
{ c: "Z", p: Params([]) },
]
@debug.assert_eq(got, want)
}