fix(svg): preserve paths before parse errors

This commit is contained in:
ldm0
2026-09-16 22:06:41 +08:00
parent 2c921abcfd
commit 6da8f584ee
4 changed files with 57 additions and 3 deletions
@@ -3095,8 +3095,7 @@ pub(super) fn svg_geometry_get_total_length_callback<'s>(
) {
let length = svg_geometry_segments(scope, args.this())
.iter()
.map(SvgGeometrySegment::length)
.sum::<f64>();
.fold(0.0, |total, segment| total + segment.length());
rv.set(v8::Number::new(scope, length).into());
}
@@ -2728,6 +2728,47 @@ fn svg_geometry_queries_use_computed_paths_live_tree_and_kurbo_bounds() {
);
}
#[test]
fn svg_path_errors_keep_valid_prefix_and_positive_zero_length() {
let mut vm = new_parsed_test_vm(
"https://svg-path-error-handling.test/",
r##"<!doctype html>
<svg xmlns="http://www.w3.org/2000/svg">
<path id="invalid" d="M 10 10 L 30 10 X 50 10"/>
<path id="empty" d=""/>
<path id="none" d="none"/>
<path id="missing_move" d="L 20 20"/>
</svg>"##,
);
let result = vm
.eval(
r#"
(() => {
const byId = id => document.getElementById(id);
const invalid = byId("invalid");
const end = invalid.getPointAtLength(invalid.getTotalLength());
return JSON.stringify({
length: invalid.getTotalLength(),
end: [end.x, end.y],
emptyIsPositiveZero: Object.is(byId("empty").getTotalLength(), 0),
noneIsPositiveZero: Object.is(byId("none").getTotalLength(), 0),
missingMoveIsPositiveZero: Object.is(
byId("missing_move").getTotalLength(),
0,
),
});
})()
"#,
)
.expect("SVG path error handling probe should evaluate");
assert_eq!(
result,
r#"{"length":20,"end":[30,10],"emptyIsPositiveZero":true,"noneIsPositiveZero":true,"missingMoveIsPositiveZero":true}"#,
);
}
#[test]
fn element_methods_and_dataset_live_on_owner_prototypes() {
let mut vm = new_storage_test_vm("https://example.com/");
+11
View File
@@ -81,6 +81,17 @@ mod tests {
assert_close(point.y, -20.0);
}
#[test]
fn path_geometry_preserves_complete_segments_before_a_parse_error() {
let invalid_command = path_segments("M 10 10 L 30 10 X 50 10");
assert_eq!(invalid_command.len(), 1);
assert_close(invalid_command[0].length(), 20.0);
let incomplete_curve = path_segments("M 10 10 L 30 10 C 40 0 50 20");
assert_eq!(incomplete_curve.len(), 1);
assert_close(incomplete_curve[0].length(), 20.0);
}
#[test]
fn path_geometry_handles_relative_commands_and_close_path() {
let segments = path_segments("m 1 1 l 3 0 v 4 h -3 z");
+4 -1
View File
@@ -4,7 +4,10 @@ use svgtypes::{SimplePathSegment, SimplifyingPathParser};
pub(crate) fn path_geometry(raw: &str) -> Option<BezPath> {
let mut path = BezPath::new();
for segment in SimplifyingPathParser::from(raw) {
match segment.ok()? {
let Ok(segment) = segment else {
break;
};
match segment {
SimplePathSegment::MoveTo { x, y } => path.move_to((x, y)),
SimplePathSegment::LineTo { x, y } => path.line_to((x, y)),
SimplePathSegment::CurveTo {