Gradient meshes: deleting mesh lines leaves a malformed mesh as it is

GradientMesh::remove_point_lines (the Mesh tool's Alt-click,
object.mesh.deletePoint) only checked that the clicked point exists,
then indexed the points above and below or left and right of it by the
mesh's rows and columns. A gradient mesh read from a document is not
checked against its rows and columns, so one with fewer points than
they need (rows 2, columns 1 and 3 points instead of 6) indexes past
the end and panics: the engine guard rolls the command back with an
internal error, and the web app, which has no guard, aborts.

It now returns false for a mesh that isn't valid, as locate (and with
it adding mesh lines), the outline and the mesh lines already do, and
the command reports that nothing could be deleted.

The test Alt-clicks an interior row's point and an interior column's
point of two such meshes and checks nothing is deleted and the mesh is
unchanged.

Reported-by: BS.ehlas.cz
This commit is contained in:
Martin Vlach
2026-10-20 09:20:24 +02:00
committed by Matej Vrzala
parent 9e7929ee89
commit da8e6af7e8
+16 -1
View File
@@ -1026,7 +1026,8 @@ impl GradientMesh {
/// Mesh tool Alt-click: delete the mesh lines through point `index` (interior lines only).
pub fn remove_point_lines(&mut self, index: usize) -> bool {
if index >= self.points.len() {
// A mesh from a file may not have the points its rows and columns need: it is indexed below.
if !self.is_valid() || index >= self.points.len() {
return false;
}
let w = self.cols as usize + 1;
@@ -1854,4 +1855,18 @@ mod tests {
m.points[1].color = Color::rgb(1.0, 0.0, 0.0);
assert!(matches!(m.color_at(0, 0, 0.5, 0.5).0, Color::Rgb { .. }));
}
/// Alt-clicking a point of a mesh from a file with fewer points than its rows and columns need
/// deletes nothing (it indexed past the points, a panic).
#[test]
fn mesh_lines_of_a_malformed_mesh_stay() {
let point = |i: u32| MeshPoint { p: Point::new(f64::from(i), 0.0), color: Color::BLACK, opacity: 1.0, handles: [Vec2::ZERO; 4] };
// An interior row's point and an interior column's point, each with 3 of the 6 points.
for (rows, cols, index) in [(2, 1, 2), (1, 2, 1)] {
let mut m = GradientMesh { rows, cols, points: (0..3).map(point).collect() };
let before = m.clone();
assert!(!m.remove_point_lines(index), "{rows}×{cols}, point {index}");
assert_eq!(m, before);
}
}
}