[graphics/krita] libs/ui/tool: Thread-safe zoom preview

Emmet O'Neill <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 2e7505044d162dd9d91ed4b8391710911fd5c871 by Emmet O'Neill, on behalf of Dat Le.
Committed on 13/08/2026 at 23:16.
Pushed by emmetoneill into branch 'master'.

Thread-safe zoom preview

M  +12   -12   libs/ui/tool/KisAsyncColorSamplerHelper.cpp
M  +2    -1    libs/ui/tool/KisAsyncColorSamplerHelper.h

https://invent.kde.org/graphics/krita/-/commit/2e7505044d162dd9d91ed4b8391710911fd5c871

diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
index 7a250fd107f..520d1fd608b 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
@@ -727,28 +727,28 @@ QImage KisAsyncColorSamplerHelper::cacheCanvasImage(QRect &canvasPixelRect) {
 
     if (m_d->cacheCanvasPreviewRect.isEmpty() || !m_d->cacheCanvasPreviewRect.contains(canvasPixelRect)) {
         // Cache an area larger than the needed preview area to avoid rapid small dynamic allocations
-        // Attempt to reduce cache size when sample size is big to reduce delay
-        qreal cacheScale = 1000;
-        // if (canvasPixelRect.width() < 250) cacheScale = 4;
-        // else if (canvasPixelRect.width() < 500) cacheScale = 2;
+        // And also avoid frequent preview delay from fetching canvas image asynchronously repeatedly
+        qreal cacheScale = 4;
 
         QRect cacheCanvasRect = canvasPixelRect;
         cacheCanvasRect.setSize(canvasPixelRect.size() * cacheScale);
         cacheCanvasRect.moveCenter(canvasPixelRect.center());
 
-        // if cache larger than canvas, then just copy whole canvas
+        // if cache requirement is larger than canvas, then just copy whole canvas
         if (cacheCanvasRect.width() >= canvasImage->width() || cacheCanvasRect.height() >= canvasImage->height()) {
             cacheCanvasRect = canvasImage->bounds();
         }
 
-        // If already fetching, then do nothing
-        if (m_d->canvasPreviewFetchingStarted) return QImage();
-
-        m_d->canvasPreviewFetchingStarted = true;
-        m_d->strokesFacade()->addJob(m_d->strokeId,
-            new KisColorSamplerStrokeStrategy::GenerateCanvasZoomPreviewData(canvasImage, cacheCanvasRect, canvasImage->profile()));
+        // If not already have a job fetching canvas image, then do it
+        // TODO: There's probably a better way to do this
+        if (!m_d->canvasPreviewFetchingStarted) {
+            m_d->canvasPreviewFetchingStarted = true;
+            m_d->strokesFacade()->addJob(m_d->strokeId,
+                new KisColorSamplerStrokeStrategy::GenerateCanvasZoomPreviewData(canvasImage, cacheCanvasRect, canvasImage->profile()));
+        }
 
-        return QImage();
+        // Instead of returning an empty QImage and cause painful flickering
+        // Just return old cache, it's not really noticeable normally. In extreme cases, we have a cool lazy loading effect :D
     }
     canvasPixelRect.translate(-m_d->cacheCanvasPreviewRect.topLeft());
 
diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.h b/libs/ui/tool/KisAsyncColorSamplerHelper.h
index 4b0513f8b32..13a955f24c3 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.h
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.h
@@ -83,8 +83,9 @@ private:
     void paintCircle(QPainter &gc, const QRectF &viewRectF, const QColor &currentColor, const QColor &baseColor);
 
     void paintCircleCrosshair(QPainter &gc, const QRectF &viewRectF, const QColor &currentColor);
+    // Return true if cache miss, will repaint later when canvas image is fetched
+    // Return false if cache hit, and painted
     bool paintCircleCanvasPreview(QPainter &gc, const QRectF &viewRectF, const QRectF &zoomDocRectF, const QPainterPath &clip);
-    // Return true if at least one reference image preview was drawn
     void paintCircleReferenceImagePreview(QPainter &gc, const QRectF &viewRectF, const QRectF &zoomDocRectF, const QPainterPath &clip);
 
     // Returns a QImage that should either contain the canvasPixelRectF, or the whole canvas if canvasPixelRectF > canvas size.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.