Merge pull request #7815 from dotCooCoo/fix/a-reverted-document-keeps-its-uid-so-a-trace

Image Trace: a trace started before Revert does not apply after it
This commit is contained in:
BFlat
2026-11-15 17:30:52 +07:00
committed by GitHub
21 changed files with 123 additions and 10 deletions
+30 -7
View File
@@ -12,6 +12,7 @@ use super::{
thread_local! {
static BOX_TESTS: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
static CANDIDATE_VISITS: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
static TRACES_ON_THIS_THREAD: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
}
// ---------- Image Trace ----------
@@ -548,15 +549,20 @@ fn color_groups(cmd: &str, d: &mut Document, items: Vec<Arc<Node>>) -> Result<Ve
Ok(seams.into_iter().chain(groups).collect())
}
/// What a trace depends on: the document it is made in, the object traced (an image, or an Image
/// Trace object traced again), its image, the image's encoded bytes, and the settings it is traced
/// with. The tracer makes the same paths of the same inputs, so a trace made away from the command
/// ([`TraceRun`]) stands in for the command's own in the same document.
/// What a trace depends on: the document it is made in and the content it was reverted to, the
/// object traced (an image, or an Image Trace object traced again), its image, the image's encoded
/// bytes, and the settings it is traced with. The tracer makes the same paths of the same inputs,
/// so a trace made away from the command ([`TraceRun`]) stands in for the command's own in the same
/// document until File › Revert replaces its content.
#[derive(Clone, Debug, PartialEq)]
struct TraceInputs {
/// The [`DocState::uid`](crate::DocState::uid) of the document traced in. A trace made in one
/// document never stands in for one in another, however alike their images and settings.
doc: u64,
/// The document's [`DocState::reverts`](crate::DocState::reverts) when the trace was prepared.
/// A trace prepared before File › Revert never stands in for one after it, even when the
/// restored image, pixels, object and settings are the same.
reverts: u64,
target: NodeId,
image: Box<ImageObject>,
/// The settings traced with, as JSON.
@@ -625,7 +631,8 @@ fn prepare(s: &Session, c: &str, p: &Value) -> Result<Prepared> {
let bytes = Arc::clone(&blob.bytes);
let library = trace_library(c, s, &mut params)?;
let traced_with = serde_json::to_value(&params).map_err(|e| EngineError::Other(e.to_string()))?;
let inputs = TraceInputs { doc: s.doc()?.uid, target, image, params: traced_with, swatches: params.swatches.clone(), bytes };
let st = s.doc()?;
let inputs = TraceInputs { doc: st.uid, reverts: st.reverts, target, image, params: traced_with, swatches: params.swatches.clone(), bytes };
Ok(Prepared { inputs, trace: params, view, params_json, preset_label, library })
}
@@ -641,7 +648,8 @@ pub struct Traced {
impl Traced {
/// Hand it to the next run of its command with the same inputs ([`TraceRun::params`]) in the
/// document it was made in, which applies it as one undo step instead of tracing again. Any
/// other trace drops it, a trace in another document included.
/// other trace drops it and traces again, a trace in another document included, and so does
/// the command after File › Revert replaced the document's content.
pub fn hand_in(self, s: &mut Session) {
s.trace_hand_off = Some(self);
}
@@ -650,6 +658,8 @@ impl Traced {
/// Decode the image bytes of `inputs` and trace them with `params`, telling `steps` how far it has
/// got ([`tr::trace_watched`]); [`EngineError::Cancelled`] once `steps` answers `false`.
fn trace_now(inputs: &TraceInputs, params: &tr::TraceParams, steps: &(dyn Fn(u64, u64) -> bool + Sync)) -> Result<Traced> {
#[cfg(test)]
TRACES_ON_THIS_THREAD.with(|n| n.set(n.get() + 1));
// An image over the tracer's size is traced scaled down (the paths are scaled back).
let raster = tr::Raster::decode_to_fit(&inputs.bytes).map_err(|e| EngineError::Other(e.to_string()))?;
if !steps(0, 0) {
@@ -725,17 +735,30 @@ impl TraceRun {
}
/// Does it still apply: would the command trace the same object, image, pixels and settings
/// now, in the document it was prepared in?
/// now, in the document it was prepared in, with no File › Revert since?
pub fn current(&self, s: &Session) -> bool {
prepare(s, self.command, &self.params).is_ok_and(|now| now.inputs == self.prepared.inputs)
}
/// Has File › Revert replaced the content of the document it was prepared in since then? False
/// when that document is no longer open.
pub fn reverted(&self, s: &Session) -> bool {
let TraceInputs { doc, reverts, .. } = self.prepared.inputs;
s.documents().iter().any(|st| st.uid == doc && st.reverts != reverts)
}
/// Decode and trace the image, telling `steps` how far it has got → what it traced, or why it
/// failed or stopped ([`EngineError::Cancelled`] once `steps` answers `false`). It touches no
/// document, so it can run on any thread.
pub fn run(&self, steps: &(dyn Fn(u64, u64) -> bool + Sync)) -> Result<Traced> {
trace_now(&self.prepared.inputs, &self.prepared.trace, steps)
}
/// How many images this thread has decoded and traced so far.
#[cfg(test)]
pub(crate) fn traces_on_this_thread() -> usize {
TRACES_ON_THIS_THREAD.with(std::cell::Cell::get)
}
}
pub(super) fn trace_make(s: &mut Session, p: &Value, expand: bool) -> Result<Value> {
+51
View File
@@ -5688,6 +5688,57 @@ fn a_trace_run_applies_only_in_its_own_document() {
}
}
/// A trace prepared before File › Revert doesn't apply after it, even when the document keeps its
/// uid and the restored image, object and settings are the same: both trace commands drop the
/// trace handed in and trace the restored image again, as one undo step. Reverting another
/// document, or a revert that fails, leaves the run current, and a trace prepared after the revert
/// applies as usual.
#[test]
fn a_trace_run_prepared_before_a_revert_does_not_apply_after_it() {
let p = json!({"params": {"ignoreWhite": true}});
for command in ["imageTrace.make", "imageTrace.makeAndExpand"] {
let mut direct = session();
image_doc(&mut direct);
let want = direct.execute(command, &p).unwrap();
let mut s = session();
let img = image_doc(&mut s);
let a = s.active_index().unwrap();
let copy = (*s.doc().unwrap().doc).clone();
let run = cmd::TraceRun::prepare(&s, command, &p).unwrap();
let traced = run.run(&|_, _| true).unwrap();
let b = s.add_document(copy.clone(), None);
assert!(s.replace_document(b, copy.clone()));
assert!(s.set_active(a));
assert!(run.current(&s) && !run.reverted(&s), "{command}: another document reverted");
assert!(!s.replace_document(s.documents().len(), copy.clone()));
assert!(run.current(&s) && !run.reverted(&s), "{command}: a revert that failed");
let (uid, reverts) = (s.doc().unwrap().uid, s.doc().unwrap().reverts);
assert!(s.replace_document(a, copy));
assert_eq!(s.doc().unwrap().uid, uid, "{command}: the tab keeps its uid");
assert_eq!(s.doc().unwrap().reverts, reverts + 1, "{command}");
assert!(!run.current(&s), "{command}: reverted");
assert!(run.reverted(&s), "{command}");
traced.hand_in(&mut s);
let traces = cmd::TraceRun::traces_on_this_thread();
let got = s.execute(run.command(), run.params()).unwrap();
assert_eq!(cmd::TraceRun::traces_on_this_thread(), traces + 1, "{command}: traced again");
assert!(s.trace_hand_off.is_none(), "{command}: dropped");
assert_eq!(got, want, "{command}");
let g = NodeId(got["id"].as_u64().unwrap());
assert_eq!(node(&s, g), node(&direct, g), "{command}");
s.execute("edit.undo", &json!({})).unwrap();
assert!(matches!(node(&s, img).kind, NodeKind::Image(_)), "{command}: one undo step");
// A trace prepared after the revert is handed in and applied without tracing again.
let after = cmd::TraceRun::prepare(&s, command, run.params()).unwrap();
let traced = after.run(&|_, _| true).unwrap();
assert!(after.current(&s) && !after.reverted(&s), "{command}: prepared after the revert");
traced.hand_in(&mut s);
let traces = cmd::TraceRun::traces_on_this_thread();
s.execute(after.command(), after.params()).unwrap();
assert_eq!(cmd::TraceRun::traces_on_this_thread(), traces, "{command}: the trace handed in applied");
}
}
/// A plug-in run that calls Image Trace and then fails leaves a trace handed in for the command in
/// place, as it leaves the document.
#[test]
+1
View File
@@ -7804,6 +7804,7 @@ breakText Glyphs Glyfy
@msg Image Trace failed: {e} Vektorizace obrazu selhala: {e}
@msg Image Trace finished, but its document was closed Vektorizace obrazu skončila, ale její dokument byl zavřen
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Vektorizace obrazu skončila, ale obraz nebo jeho nastavení se mezitím změnily: vektorizujte ho znovu
@msg Image Trace finished, but its document was reverted: trace it again Vektorizace obrazu skončila, ale její dokument byl vrácen k uložené verzi: vektorizujte ho znovu
@msg Import SVG Filter reads SVG files, not SVGZ Importovat filtr SVG čte soubory SVG, ne SVGZ
@msg Invalid dimension offset Neplatné odsazení kóty
@msg Invalid point Neplatný bod
Can't render this file because it is too large.
+1
View File
@@ -7650,6 +7650,7 @@ breakText Glyphs Glyphen
@msg Image Trace failed: {e} Bildnachzeichner fehlgeschlagen: {e}
@msg Image Trace finished, but its document was closed Bildnachzeichner abgeschlossen, aber sein Dokument wurde geschlossen
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Bildnachzeichner abgeschlossen, aber das Bild oder seine Einstellungen haben sich inzwischen geändert: Zeichnen Sie es erneut nach
@msg Image Trace finished, but its document was reverted: trace it again Bildnachzeichner abgeschlossen, aber sein Dokument wurde auf die letzte Version zurückgesetzt: Zeichnen Sie es erneut nach
@msg Invalid dimension offset Ungültiger Bemaßungsversatz
@msg Invalid point Ungültiger Punkt
@msg Join: a subpath went missing Zusammenfügen: Ein Teilpfad ist verloren gegangen
Can't render this file because it is too large.
+1
View File
@@ -7672,6 +7672,7 @@ breakText Glyphs Glyphes
@msg Image Trace failed: internal error: its thread stopped (please report this bug) Échec de la vectorisation de l’image : erreur interne : son thread s’est arrêté (merci de signaler ce bogue)
@msg Image Trace failed: {e} Échec de la vectorisation de l’image : {e}
@msg Image Trace finished, but its document was closed La vectorisation de l’image est terminée, mais son document a été fermé
@msg Image Trace finished, but its document was reverted: trace it again La vectorisation de l’image est terminée, mais son document a été rétabli à la version précédente : vectorisez-la à nouveau
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again La vectorisation de l’image est terminée, mais l’image ou ses réglages ont changé entre-temps : vectorisez-la à nouveau
@msg Import SVG Filter reads SVG files, not SVGZ Importer un filtre SVG lit les fichiers SVG, pas SVGZ
@msg Invalid dimension offset Décalage de cote non valide
Can't render this file because it is too large.
+1
View File
@@ -7117,6 +7117,7 @@ antiAlias Sharp शार्प
@msg Image Trace failed: internal error: its thread stopped (please report this bug) इमेज ट्रेस विफल: आंतरिक त्रुटि: इसके धागे को बंद कर दिया (कृपया इस बग की रिपोर्ट करें)
@msg Image Trace finished, but its document was closed इमेज ट्रेस समाप्त हो गया, लेकिन इसका डॉक्यूमेंट बंद हो गया।
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again इमेज ट्रेस समाप्त हो गया, लेकिन इस बीच इमेज या इसकी सेटिंग्स बदल गई: इसे फिर से ट्रेस करें
@msg Image Trace finished, but its document was reverted: trace it again इमेज ट्रेस समाप्त हो गया, लेकिन इसके डॉक्यूमेंट को मूल स्थिति में लाया गया: इसे फिर से ट्रेस करें
@msg Image Trace: the traced image is missing इमेज ट्रेस: ज्ञात इमेज गायब है
@msg image would be too large; lower the resolution इमेज बहुत बड़ी होगी; रिज़ॉल्यूशन कम करें
@msg imageMap `{m}`: none, client or server imageMap `{m}`: none, client या server
Can't render this file because it is too large.
+1
View File
@@ -7674,6 +7674,7 @@ breakText Glyphs Glifák
@msg Image Trace failed: {e} A képvektorizálás nem sikerült: {e}
@msg Image Trace finished, but its document was closed A képvektorizálás elkészült, de a dokumentumát bezárták
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again A képvektorizálás elkészült, de a kép vagy a beállításai közben megváltoztak: vektorizáld újra
@msg Image Trace finished, but its document was reverted: trace it again A képvektorizálás elkészült, de a dokumentumát visszaállították a mentett változatra: vektorizáld újra
@msg Import SVG Filter reads SVG files, not SVGZ Az SVG-szűrő importálása SVG-fájlokat olvas, SVGZ-fájlokat nem
@msg Invalid dimension offset Érvénytelen méretvonal-eltolás
@msg Invalid point Érvénytelen pont
Can't render this file because it is too large.
+1
View File
@@ -7700,6 +7700,7 @@ breakText Glyphs Glifi
@msg Image Trace failed: {e} Ricalco immagine non riuscito: {e}
@msg Image Trace finished, but its document was closed Ricalco immagine terminato, ma il suo documento è stato chiuso
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Ricalco immagine terminato, ma nel frattempo l'immagine o le sue impostazioni sono cambiate: ricalcala di nuovo
@msg Image Trace finished, but its document was reverted: trace it again Ricalco immagine terminato, ma il suo documento è stato ripristinato: ricalcala di nuovo
@msg Invalid dimension offset Distanza della quota non valida
@msg Invalid point Punto non valido
@msg Join: a subpath went missing Unisci: un sottotracciato è andato perso
Can't render this file because it is too large.
+1
View File
@@ -6901,6 +6901,7 @@ axis Y Axis Y 軸
@msg Image Trace failed: {e} 画像トレースに失敗しました: {e}
@msg Image Trace finished, but its document was closed 画像トレースは完了しましたが、ドキュメントが閉じられています
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again 画像トレースは完了しましたが、その間に画像または設定が変更されました: もう一度トレースしてください
@msg Image Trace finished, but its document was reverted: trace it again 画像トレースは完了しましたが、ドキュメントは保存済みの状態に戻されました: もう一度トレースしてください
@msg Invalid dimension offset 寸法のオフセットが無効です
@msg Invalid point 点が無効です
@msg Join: a subpath went missing 連結: サブパスが見つからなくなりました
Can't render this file because it is too large.
+1
View File
@@ -7399,6 +7399,7 @@ breakText Glyphs 글리프
@msg Image Trace failed: {e} 이미지 추적 실패: {e}
@msg Image Trace finished, but its document was closed 이미지 추적이 끝났지만 문서가 닫혔습니다
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again 이미지 추적이 끝났지만 그 사이에 이미지나 설정이 바뀌었습니다: 다시 추적하세요
@msg Image Trace finished, but its document was reverted: trace it again 이미지 추적이 끝났지만 문서가 되돌려졌습니다: 다시 추적하세요
@msg Import SVG Filter reads SVG files, not SVGZ SVG 필터 가져오기는 SVGZ가 아닌 SVG 파일을 읽습니다
@msg Invalid dimension offset 잘못된 치수 오프셋
@msg Invalid point 잘못된 점
Can't render this file because it is too large.
+1
View File
@@ -5726,6 +5726,7 @@ imageTrace Outline Contour
@msg Image Trace failed: {e} Afbeelding traceren is mislukt: {e}
@msg Image Trace finished, but its document was closed Afbeelding traceren is voltooid, maar het document ervan is gesloten
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Afbeelding traceren is voltooid, maar de afbeelding of de instellingen ervan zijn intussen gewijzigd: traceer de afbeelding opnieuw
@msg Image Trace finished, but its document was reverted: trace it again Afbeelding traceren is voltooid, maar het document ervan is teruggezet: traceer de afbeelding opnieuw
@msg Import SVG Filter reads SVG files, not SVGZ SVG-filter importeren leest SVG-bestanden, geen SVGZ
@msg Invalid dimension offset Ongeldige verschuiving van de maatlijn
@msg Invalid point Ongeldig punt
Can't render this file because it is too large.
+1
View File
@@ -7943,6 +7943,7 @@ breakText Glyphs Glify
@msg Image Trace failed: {e} Obrys obrazu nie powiódł się: {e}
@msg Image Trace finished, but its document was closed Obrys obrazu został ukończony, ale jego dokument został zamknięty
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Obrys obrazu został ukończony, ale obraz lub jego ustawienia zmieniły się w międzyczasie: obrysuj go ponownie
@msg Image Trace finished, but its document was reverted: trace it again Obrys obrazu został ukończony, ale jego dokument został przywrócony: obrysuj go ponownie
@msg Join: a subpath went missing Połącz: brakuje ścieżki podrzędnej
@msg Lock Workspace is not available in VectorCraft Polecenie Zablokuj obszar roboczy nie jest dostępne w programie VectorCraft
@msg Move Panel to New Window is not available: floating panels stay in the main window Polecenie Przenieś panel do nowego okna nie jest dostępne: panele pływające pozostają w oknie głównym
Can't render this file because it is too large.
+1
View File
@@ -7866,6 +7866,7 @@ swatch Yellow Green Verde-amarelado
@msg Image Trace failed: {e} O Rastreamento de Imagem falhou: {e}
@msg Image Trace finished, but its document was closed O Rastreamento de Imagem terminou, mas o documento dele foi fechado
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again O Rastreamento de Imagem terminou, mas a imagem ou as configurações dela mudaram nesse meio-tempo: rastreie-a novamente
@msg Image Trace finished, but its document was reverted: trace it again O Rastreamento de Imagem terminou, mas o documento dele foi revertido: rastreie-a novamente
@msg Import SVG Filter reads SVG files, not SVGZ Importar Filtro SVG lê arquivos SVG, não SVGZ
@msg Invalid dimension offset Deslocamento de cota inválido
@msg Invalid point Ponto inválido
Can't render this file because it is too large.
+1
View File
@@ -8205,6 +8205,7 @@ digits Hindi Hindi
@msg Image Trace failed: internal error: its thread stopped (please report this bug) Bildkalkering misslyckades: internt fel: dess tråd stoppades (rapportera gärna felet)
@msg Image Trace finished, but its document was closed Bildkalkeringen är klar, men dess dokument har stängts
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Bildkalkeringen är klar, men bilden eller dess inställningar ändrades under tiden: vektorisera den igen
@msg Image Trace finished, but its document was reverted: trace it again Bildkalkeringen är klar, men dess dokument har återgått till sparad version: vektorisera den igen
@msg imageMap `{m}`: none, client or server imageMap `{m}`: none, client eller server
@msg index out of range index utanför intervallet
@msg instances must be 1..1000 instances måste vara 1..1000
Can't render this file because it is too large.
+1
View File
@@ -7284,6 +7284,7 @@ axis Y Axis Y ekseni
@msg Image Trace failed: {e} Görüntü İzleme başarısız oldu: {e}
@msg Image Trace finished, but its document was closed Görüntü İzleme tamamlandı, ancak belgesi kapatılmıştı
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Görüntü İzleme tamamlandı, ancak bu sırada görüntü veya ayarları değişti: yeniden izleyin
@msg Image Trace finished, but its document was reverted: trace it again Görüntü İzleme tamamlandı, ancak belgesi geri döndürüldü: yeniden izleyin
@msg Invalid dimension offset Geçersiz boyut ofseti
@msg Invalid point Geçersiz nokta
@msg Join: a subpath went missing Birleştir: bir alt yol kayboldu
Can't render this file because it is too large.
+1
View File
@@ -7410,6 +7410,7 @@ breakText Glyphs Гліфи
@msg Image Trace failed: {e} Трасування зображення не вдалося: {e}
@msg Image Trace finished, but its document was closed Трасування зображення завершено, але його документ закрито
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again Трасування зображення завершено, але зображення або його параметри тим часом змінилися: виконайте трасування ще раз
@msg Image Trace finished, but its document was reverted: trace it again Трасування зображення завершено, але його документ було повернуто до збереженої версії: виконайте трасування ще раз
@msg Import SVG Filter reads SVG files, not SVGZ Імпорт фільтра SVG читає файли SVG, а не SVGZ
@msg Invalid dimension offset Неприпустиме зміщення розміру
@msg Invalid point Неприпустима точка
Can't render this file because it is too large.
+1
View File
@@ -7927,6 +7927,7 @@ breakText Glyphs 字形
@msg Image Trace failed: {e} 图像描摹失败:{e}
@msg Image Trace finished, but its document was closed 图像描摹已完成,但其文档已关闭
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again 图像描摹已完成,但图像或其设置在此期间发生了更改:请重新描摹
@msg Image Trace finished, but its document was reverted: trace it again 图像描摹已完成,但其文档已恢复:请重新描摹
@msg Invalid dimension offset 尺寸标注的偏移无效
@msg Invalid point 点无效
@msg Join: a subpath went missing 连接:有一条子路径丢失
Can't render this file because it is too large.
+1
View File
@@ -7855,6 +7855,7 @@ breakText Glyphs 字符
@msg Image Trace failed: {e} 影像描圖失敗:{e}
@msg Image Trace finished, but its document was closed 影像描圖已完成,但其文件已關閉
@msg Image Trace finished, but the image or its settings changed meanwhile: trace it again 影像描圖已完成,但影像或其設定在此期間已變更:請重新描圖
@msg Image Trace finished, but its document was reverted: trace it again 影像描圖已完成,但其文件已回復:請重新描圖
@msg Invalid dimension offset 尺寸標註位移無效
@msg Invalid point 點無效
@msg Join: a subpath went missing 連接:有一條子路徑不見了
Can't render this file because it is too large.
+17
View File
@@ -162,6 +162,23 @@ fn a_trace_needs_its_image_as_it_was() {
assert!(app.ui.status.contains("changed meanwhile: trace it again"), "{}", app.ui.status);
}
/// A trace started before File › Revert doesn't apply after it, even when the document was
/// reverted to the same image: nothing changes, and the status bar says why.
#[test]
fn a_trace_started_before_a_revert_does_not_apply() {
let mut app = app();
let i = app.session.active_index().unwrap();
let copy = (*app.session.doc().unwrap().doc).clone();
let [img] = app.session.doc().unwrap().selection.objects[..] else { panic!("the image is selected") };
crate::menus::invoke(&mut app, "imageTrace.make", json!({"preset": "Default"}));
assert!(app.session.replace_document(i, copy));
wait(&mut app);
assert_eq!(undos(&app), 0, "nothing changes");
let st = app.session.doc().unwrap();
assert!(matches!(st.doc.node(img).unwrap().kind, vectorcraft_doc::NodeKind::Image(_)), "the image is not traced");
assert_eq!(app.ui.status, "Image Trace finished, but its document was reverted: trace it again");
}
/// The progress window opens after its delay with Cancel and Continue in Background; Continue in
/// Background closes it and the trace goes on.
#[test]
+8 -3
View File
@@ -8,7 +8,8 @@
//!
//! When it is done, what it traced is handed to its command with the same parameters
//! ([`Traced::hand_in`]), so the edit is one undo step like any trace, unless the image or the
//! settings changed meanwhile: then nothing changes and the status bar says to trace it again. The
//! settings changed meanwhile or File › Revert replaced the document's content: then nothing
//! changes and the status bar says to trace it again. The
//! control channel, MCP and scripts run the commands at once, and so does every trace on the web,
//! in unit tests that don't set `off_the_ui_thread`, and with `VECTORCRAFT_SYNC_OPEN` set
//! ([`available`]).
@@ -158,8 +159,8 @@ pub fn poll(app: &mut VectorcraftApp) {
}
/// Applies trace `r`'s result in its document, which becomes the active one again, as its command
/// would while the object, its image and the settings are as they were; else why it has none, in
/// the status bar.
/// would while the object, its image and the settings are as they were and the document was not
/// reverted; else why it has none, in the status bar.
fn finish(app: &mut VectorcraftApp, r: Running, done: Option<Done>) {
// Cancel changes nothing, even when the trace ended just before it.
if r.token.is_cancelled() {
@@ -184,6 +185,10 @@ fn finish(app: &mut VectorcraftApp, r: Running, done: Option<Done>) {
return;
};
app.session.set_active(i);
if run.reverted(&app.session) {
app.status("Image Trace finished, but its document was reverted: trace it again");
return;
}
if !run.current(&app.session) {
app.status("Image Trace finished, but the image or its settings changed meanwhile: trace it again");
return;
+1
View File
@@ -1523,6 +1523,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
- **Image Trace, Flat Logo working size:** Flat Logo traces at most 1024 px on a side; a larger image is averaged down by a whole factor first, and the trace's `warnings` name the size it was traced at and the image's own size, in place of the slower-trace and 64-megapixel notes; code-drawn 1024 and 1025 px tests in `crates/trace` and `crates/engine`.
- **Image Trace, Preview:** the Image Trace panel's Preview checkbox, before Trace, is on by default, and a setting change traces the selected Image Trace object again at once. Off, changes wait in the panel until Trace applies them as one undo step, or until Preview is turned on again. Changes stay with the object they were made for while another object is selected. When Preview is turned on with that object not selected, the object is traced with its changes when it is selected again. Preview is kept with the UI preferences, and Reset to Default leaves it. The `imageTrace.preview` command turns it on or off.
- **Image Trace, traces made off the UI thread stay with their document:** a trace made away from the command (`TraceRun`) applies only in the document it was made in. In another open document with the same image, object and settings, `imageTrace.make` and `imageTrace.makeAndExpand` drop it and trace that document's image, as one undo step (VectorCraft's own rule). Test: `a_trace_run_applies_only_in_its_own_document` in `crates/engine`. Scores and hours unchanged.
- **Image Trace, a trace started before File › Revert does not apply after it:** the reverted document keeps its tab, but a trace prepared before the revert no longer applies, even when the restored image, object and settings are the same. A background trace that finishes after the revert changes nothing and the status bar says the document was reverted; a result handed to `imageTrace.make` or `imageTrace.makeAndExpand` is dropped and the restored image is traced again, as one undo step. Reverting another document, or a revert that fails, does not affect the trace (VectorCraft's own rule). Tests: `a_trace_run_prepared_before_a_revert_does_not_apply_after_it` in `crates/engine`, `a_trace_started_before_a_revert_does_not_apply` in `crates/ui-egui`. Scores and hours unchanged.
- **Image Trace small contours:** closed fits too small to form an editable subpath retain their positioned outline, including holes. Source-generated island, hole/winding and stepped-region regressions cover Corners and Noise; defaults, parity scores and estimates are unchanged.
- **Image Trace, custom presets:** Manage Presets next to the Image Trace panel's Preset dropdown saves the panel's settings as a new preset under a name (Save as New Preset…) and renames or deletes the saved preset shown; built-in presets don't change. Saved presets are kept with the preferences and follow the built-in ones in the panel, Control bar and Properties preset lists. `imageTrace.presets.save` and `imageTrace.presets.delete` save, rename and delete them, `imageTrace.presets` lists them, and `imageTrace.make {preset}` traces with one by name.
- **Image Trace, preset buttons:** six buttons above the Image Trace panel's Preset dropdown choose a preset as the dropdown does, for the options the [help page](https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/image-trace-panel-options.html) lists before Preset. The presets each button chooses are VectorCraft's own: Auto Color chooses Auto Color, High Color chooses High Fidelity Photo, Low Color chooses Low Fidelity Photo, Grayscale chooses Shades of Gray, Black and White chooses Black and White Logo, and Outline chooses Outline. With Preview on, a click traces the selected Image Trace object again as one undo step; with nothing traced selected, it changes the panel's settings only. The button of the panel's preset shows as selected.