perf(canvas): patch scene fill/stroke in place on colour-picker drag
A colour-picker drag rewrites doc fill on every mouse-move, so the scene build cache (which compares the doc) rebuilt the whole layout — taffy + a full SceneNode reshape — per drag frame, even though a solid colour change touches no layout. Mirror the node-drag fast path: patch the anchor's resolved scene fill / stroke via LayoutScene::set_node_fill / set_node_stroke_color and invalidate the cache, skipping mark_dirty so the patch survives the frame. Variable-mode, instance redirects, gradient-stop / effect targets, and brand-new strokes fall back to the full rebuild. Bumps vendor/jian to a86832d (the scene-patch methods). Native only; the web host's live-sync push gate needs the same wiring once its spine settles.
This commit is contained in:
parent
25a5b02ce2
commit
e839c40770
|
|
@ -371,6 +371,54 @@ impl WidgetHostNative {
|
|||
true
|
||||
}
|
||||
|
||||
/// Patch the live scene's resolved fill / stroke for the active
|
||||
/// colour-picker drag without a layout rebuild. Returns `true` when the
|
||||
/// patch applied (caller skips `mark_dirty`); `false` when the edit is
|
||||
/// not in the patchable set — variable-mode, an instance redirect, a
|
||||
/// gradient-stop / effect target, or a node not solid-patchable — and
|
||||
/// the caller must rebuild for correctness.
|
||||
fn try_patch_color_drag(&mut self, is_instance: bool) -> bool {
|
||||
use op_editor_core::ui_draft::ColorTarget;
|
||||
use op_editor_ui::widgets::color_picker::hsv_to_rgb;
|
||||
if is_instance || self.editor_state_dirty {
|
||||
return false;
|
||||
}
|
||||
let Some(state) = self.editor_state.ui.color_picker.as_ref() else {
|
||||
return false;
|
||||
};
|
||||
// Variable-mode writes fan out to every node referencing the
|
||||
// variable — far beyond the anchor — so let the rebuild repaint.
|
||||
if state.variable.is_some() {
|
||||
return false;
|
||||
}
|
||||
let is_fill = match state.target {
|
||||
ColorTarget::Fill => true,
|
||||
ColorTarget::Stroke => false,
|
||||
// GradientStop / EffectColor touch gradient bodies / effects
|
||||
// the scene patch does not model — rebuild instead.
|
||||
_ => return false,
|
||||
};
|
||||
let color = hsv_to_rgb(state.hue, state.sat, state.val);
|
||||
let anchor = self.editor_state.selection.anchor.clone();
|
||||
if !anchor.is_real() || !self.editor_state.is_editable(&anchor) {
|
||||
return false;
|
||||
}
|
||||
let ids = [anchor.as_str().to_string()];
|
||||
let patched = if is_fill {
|
||||
self.layout_scene.set_node_fill(&ids, color)
|
||||
} else {
|
||||
self.layout_scene.set_node_stroke_color(&ids, color)
|
||||
};
|
||||
if patched {
|
||||
// The scene now drifts from the cached build inputs; invalidate
|
||||
// so a later refresh always rebuilds from the canonical doc
|
||||
// (mirrors the node-drag patch path — otherwise an undo back to
|
||||
// the cached colour would skip the rebuild and leave the patch).
|
||||
self.scene_cache.invalidate();
|
||||
}
|
||||
patched
|
||||
}
|
||||
|
||||
pub fn apply_cursor_move(&mut self, x: f32, y: f32) -> bool {
|
||||
// In-flight VariablesPanel edge resize — owns the cursor.
|
||||
if self.variables_resize.is_some()
|
||||
|
|
@ -425,6 +473,7 @@ impl WidgetHostNative {
|
|||
// Instance-write redirect (GAP #10) — picker drags on
|
||||
// a Ref anchor route the live colour into descendants.
|
||||
let instance_scope = self.editor_state.begin_instance_write_for_anchor();
|
||||
let is_instance = instance_scope.is_some();
|
||||
match kind {
|
||||
ColorPickerDrag::SvBox => {
|
||||
let (s, v) = picker.sv_at(panel, point);
|
||||
|
|
@ -440,7 +489,15 @@ impl WidgetHostNative {
|
|||
if let Some(scope) = instance_scope {
|
||||
self.editor_state.finish_instance_write(scope);
|
||||
}
|
||||
self.mark_dirty();
|
||||
// A solid Fill/Stroke change on a concrete anchor touches
|
||||
// no layout, so patch the resolved scene paint in place
|
||||
// rather than re-running taffy + reshape on every drag
|
||||
// frame (mirrors the node-drag `translate_nodes` fast
|
||||
// path). Variable-mode, instance redirects, gradient-stop /
|
||||
// effect targets, and new strokes fall back to a rebuild.
|
||||
if !self.try_patch_color_drag(is_instance) {
|
||||
self.mark_dirty();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
vendor/jian
vendored
2
vendor/jian
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 27086661dbd76ef4b932ee382431d6dc2d55ffa1
|
||||
Subproject commit 1565f66f024a12c3020a43848d0312aa94c51aa9
|
||||
Loading…
Reference in a new issue