From 531342825095e0703d251c38e382e293289b263b Mon Sep 17 00:00:00 2001 From: Ad5001 Date: Tue, 15 Oct 2024 03:52:06 +0200 Subject: [PATCH] Improving stability of asynchronous LaTeX renderer. --- common/src/module/canvas.mjs | 16 +++++++++++----- common/src/preferences/general.mjs | 2 +- runtime-pyside6/LogarithmPlotter/util/promise.py | 7 ++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/common/src/module/canvas.mjs b/common/src/module/canvas.mjs index c46c9a1..62649cf 100644 --- a/common/src/module/canvas.mjs +++ b/common/src/module/canvas.mjs @@ -30,16 +30,18 @@ class CanvasAPI extends Module { #canvas = null /** @type {CanvasRenderingContext2D} */ #ctx = null + /** Lock to prevent asynchronous stuff from printing stuff that is outdated. */ + #redrawCount = 0 /** @type {{show(string, string, string)}} */ #drawingErrorDialog = null - - + + constructor() { super("Canvas", { canvas: CanvasInterface, drawingErrorDialog: DialogInterface }) - + /** * * @type {Object.} @@ -207,6 +209,7 @@ class CanvasAPI extends Module { */ redraw() { if(!this.initialized) throw new Error("Attempting redraw before initialize!") + this.#redrawCount = (this.#redrawCount + 1) % 10000 this.#ctx = this.#canvas.getContext("2d") this._computeAxes() this._reset() @@ -519,15 +522,18 @@ class CanvasAPI extends Module { * @param {function(LatexRenderResult|{width: number, height: number, source: string})} callback */ renderLatexImage(ltxText, color, callback) { + const currentRedrawCount = this.#redrawCount const onRendered = (imgData) => { if(!this.#canvas.isImageLoaded(imgData.source) && !this.#canvas.isImageLoading(imgData.source)) { // Wait until the image is loaded to callback. this.#canvas.loadImageAsync(imgData.source).then(() => { - callback(imgData) + if(this.#redrawCount === currentRedrawCount) + callback(imgData) }) } else { // Callback directly - callback(imgData) + if(this.#redrawCount === currentRedrawCount) + callback(imgData) } } const prerendered = Latex.findPrerendered(ltxText, this.textsize, color) diff --git a/common/src/preferences/general.mjs b/common/src/preferences/general.mjs index 4a1098f..a6957c6 100644 --- a/common/src/preferences/general.mjs +++ b/common/src/preferences/general.mjs @@ -47,7 +47,7 @@ class EnableLatex extends BoolSetting { } const ENABLE_LATEX_ASYNC = new BoolSetting( - qsTranslate("general", "Enable asynchronous LaTeX renderer (experimental)"), + qsTranslate("general", "Enable asynchronous LaTeX renderer"), "enable_latex_async", "new" ) diff --git a/runtime-pyside6/LogarithmPlotter/util/promise.py b/runtime-pyside6/LogarithmPlotter/util/promise.py index 6868432..f129d41 100644 --- a/runtime-pyside6/LogarithmPlotter/util/promise.py +++ b/runtime-pyside6/LogarithmPlotter/util/promise.py @@ -53,7 +53,12 @@ class PyPromiseRunner(QRunnable): raise InvalidReturnValue("Must return either a primitive, a valid QObject, JS Value, or None.") self.promise.finished.emit(data) except Exception as e: - self.promise.errored.emit(repr(e)) + try: + self.promise.errored.emit(repr(e)) + except RuntimeError as e2: + # Happens when the PyPromise has already been garbage collected. + # In other words, nothing to report to nowhere. + pass class PyPromise(QObject):