fix(shell): defensive commit_layer_drag source-validity guard

Final codex re-review CONCERN: `commit_layer_drag` was relying on
`Document::reorder_before/after`'s own source-existence check to
no-op on a deleted source. Per codex: the commit path should bail
explicitly for symmetry with the existing cursor_move + paint
guards. Added the same `active_page().find(source).is_none()`
check on both native (`widget_host/input.rs`) and web
(`widget_host.rs`) at the top of `commit_layer_drag`, right after
the `!d.active` early-out.

No behavior change in the safe path (reorder still happens), but
short-circuits the drop_target_at + dispatch when the source is
gone.
This commit is contained in:
Kayshen-X 2026-05-12 02:21:59 +08:00
parent 33ee2f37ed
commit b11f064e79
2 changed files with 23 additions and 0 deletions

View file

@ -378,6 +378,19 @@ impl WidgetHostNative {
// only effect, nothing more to do.
return false;
}
// Defensive source-validity check — symmetric with the
// cursor_move and paint guards. `reorder_before/after`
// already silently no-ops on a missing source, but bailing
// here keeps the rest of this method (drop_target_at +
// dispatch) from running pointlessly on a dead drag.
if self
.document
.active_page()
.map(|p| p.find(d.source).is_none())
.unwrap_or(true)
{
return false;
}
use openpencil_shell_core::widgets::{DropPosition, LayerPanel, TOP_BAR_HEIGHT};
let layer_rect = openpencil_shell_core::Rect {
origin: openpencil_shell_core::Point2D::new(0.0, TOP_BAR_HEIGHT),

View file

@ -465,6 +465,16 @@ impl WidgetHost {
if !d.active {
return false;
}
// Defensive source-validity check (mirrors native) — bail
// if the dragged node disappeared between move and release.
if self
.document
.active_page()
.map(|p| p.find(d.source).is_none())
.unwrap_or(true)
{
return false;
}
use openpencil_shell_core::widgets::{DropPosition, LayerPanel};
let layer_rect = self.layer_panel_rect(viewport_h);
let panel = LayerPanel::from_document(&self.document);