Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_canvas2.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 *
3 * SPDX-FileCopyrightText: 2006, 2010 Boudewijn Rempt <boud@valdyas.org>
4 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
5 * SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10#include "kis_canvas2.h"
11
12#include <functional>
13#include <numeric>
14
15#include <QApplication>
16#include <QWidget>
17#include <QVBoxLayout>
18#include <QTime>
19#include <QMouseEvent>
20#include <QScreen>
21#include <QScreen>
22#include <QWindow>
23
24#include <kis_debug.h>
25
26#include <KoUnit.h>
27#include <KoShapeManager.h>
29#include <KoColorProfile.h>
31#include <KisDocument.h>
32#include <KoSelection.h>
33#include <KoShapeController.h>
35
36#include <KisUsageLogger.h>
37
38#include <kis_lod_transform.h>
39#include "kis_tool_proxy.h"
42#include "kis_image.h"
43#include "KisImageBarrierLock.h"
44#include "kis_undo_adapter.h"
47#include "KisViewManager.h"
48#include "kis_config.h"
49#include "kis_config_notifier.h"
51#include "kis_qpainter_canvas.h"
52#include "kis_group_layer.h"
54#include "kis_node_manager.h"
55#include "kis_selection.h"
58#include "kis_selection_mask.h"
59#include "kis_image_config.h"
65#include "KisView.h"
67#include "kis_grid_config.h"
68#include "KisMainWindow.h"
69
73#include "opengl/kis_opengl.h"
74#include "kis_fps_decoration.h"
75
78
80#include <kis_popup_palette.h>
81
84
86
89
90#include "kis_wrapped_rect.h"
91#include "kis_algebra_2d.h"
93
95#include "KisDisplayConfig.h"
96#include "config-qt-patches-present.h"
97#include <KoIcon.h>
98
99#include <config-use-surface-color-management-api.h>
100#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
101
105
106#endif /* KRITA_USE_SURFACE_COLOR_MANAGEMENT_API */
107
110#include <KisCanvasState.h>
111
112
113class Q_DECL_HIDDEN KisCanvas2::KisCanvas2Private
114{
121 {
122 KisCanvas2Private * m_canvasPrivateRef = nullptr;
124 CanvasInputActionGroupsMaskInterface(KisCanvas2Private * canvasPrivateRef)
125 :m_canvasPrivateRef(canvasPrivateRef)
126 { }
127 KisInputActionGroupsMask inputActionGroupsMask() const override
128 {
129 Q_ASSERT(m_canvasPrivateRef); // this method should only be used upon creating a KisInputActionGroupsMaskGuard
130 return m_canvasPrivateRef->inputActionGroupsMask;
131 }
132 void setInputActionGroupsMask(KisInputActionGroupsMask mask) override
133 {
134 if(m_canvasPrivateRef)
135 m_canvasPrivateRef->inputActionGroupsMask = mask;
136 }
137 }; // class CanvasInputActionGroupsMask
138
139public:
141 KisCoordinatesConverter *coordConverter,
143 KoCanvasResourceProvider *resourceManager)
144 : q(parent)
145 , coordinatesConverter(coordConverter)
146 , view(view)
147 , shapeManager(parent)
148 , selectedShapesProxy(&shapeManager)
149 , toolProxy(parent)
150 , proofingConfig(new KisProofingConfiguration)
151 , displayColorConverter(resourceManager, view)
152 , inputActionGroupsMaskInterface(new CanvasInputActionGroupsMaskInterface(this))
153 , regionOfInterestUpdateCompressor(100, KisSignalCompressor::FIRST_INACTIVE)
154 , referencesBoundsUpdateCompressor(100, KisSignalCompressor::FIRST_INACTIVE)
155 {
156#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
157 if (KisPlatformPluginInterfaceFactory::instance()->surfaceColorManagedByOS()) {
158 rootSurfaceInfoProxy = new KisRootSurfaceInfoProxy(view, q);
159 multiSurfaceSetupManager.setRootSurfaceInfoProxy(rootSurfaceInfoProxy);
160 connect(rootSurfaceInfoProxy,
162 parent,
163 [this](const KoColorProfile *profile) {
164 if (!multiSurfaceState)
165 return;
166 auto newState = multiSurfaceSetupManager.onGuiSurfaceFormatChanged(*multiSurfaceState, profile);
167 assignChangedMultiSurfaceState(newState);
168 });
169 }
170#endif
171 }
172
174 {
175 inputActionGroupsMaskInterface->m_canvasPrivateRef = nullptr;
176
177 // We need to make sure that the QScopedPointer gets freed within the scope
178 // of KisCanvas2Private's lifespan. For some reason, this isn't guaranteed
179 // and was causing a crash when closing a file when playback is happening
180 // and there are multiple images. See Bug: 499658
181 animationPlayer.reset();
182 }
183
184
186 KisCoordinatesConverter *coordinatesConverter = 0;
188 KisAbstractCanvasWidget *canvasWidget = 0;
191 bool currentCanvasIsOpenGL = true;
192 int openGLFilterMode = 0;
195
196#if !KRITA_QT_HAS_UPDATE_COMPRESSION_PATCH
198#endif
201 bool updateSceneRequested = false;
202
203 QBitArray channelFlags;
205 bool proofingConfigUpdated = false;
206
207 KisPopupPalette *popupPalette = 0;
209
211 QScopedPointer<KisCanvasAnimationState> animationPlayer;
213 bool lodPreferredInImage = false;
214 bool bootstrapLodBlocked = false;
216 KisInputActionGroupsMask inputActionGroupsMask = AllActionGroup;
217
219
221
225 qreal regionOfInterestMargin = 0.25;
226
228 int isBatchUpdateActive = 0;
229
230
231#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
232 QScopedPointer<KisCanvasSurfaceColorSpaceManager> surfaceColorManager;
233 KisRootSurfaceInfoProxy *rootSurfaceInfoProxy;
234#endif
236 std::optional<KisMultiSurfaceStateManager::State> multiSurfaceState;
237
239 return lodPreferredInImage && !bootstrapLodBlocked;
240 }
241
242 bool lodIsSupported() const {
243 return currentCanvasIsOpenGL &&
245 (openGLFilterMode == KisOpenGL::TrilinearFilterMode ||
246 openGLFilterMode == KisOpenGL::HighQualityFiltering);
247 }
248
250
251 QRect docUpdateRectToWidget(const QRectF &docRect);
252
253 int currentScreenId() const {
254 int canvasScreenNumber = qApp->screens().indexOf(view->currentScreen());
255
256 if (canvasScreenNumber < 0) {
257 warnKrita << "Couldn't detect screen that Krita belongs to..." << ppVar(view->currentScreen());
258 canvasScreenNumber = 0;
259 }
260 return canvasScreenNumber;
261 }
262
265};
266
267namespace {
268KoShapeManager* fetchShapeManagerFromNode(KisNodeSP node)
269{
270 KoShapeManager *shapeManager = 0;
271 KisSelectionSP selection;
272
273 if (KisLayer *layer = dynamic_cast<KisLayer*>(node.data())) {
274 KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(layer);
275 if (shapeLayer) {
276 shapeManager = shapeLayer->shapeManager();
277
278 }
279 } else if (KisSelectionMask *mask = dynamic_cast<KisSelectionMask*>(node.data())) {
280 selection = mask->selection();
281 }
282
283 if (!shapeManager && selection && selection->hasShapeSelection()) {
284 KisShapeSelection *shapeSelection = dynamic_cast<KisShapeSelection*>(selection->shapeSelection());
285 KIS_ASSERT_RECOVER_RETURN_VALUE(shapeSelection, 0);
286
287 shapeManager = shapeSelection->shapeManager();
288 }
289
290 return shapeManager;
291}
292}
293
295 : KoCanvasBase(sc, resourceManager)
296 , m_d(new KisCanvas2Private(this, coordConverter, view, resourceManager))
297{
303 m_d->bootstrapLodBlocked = true;
304 connect(mainWindow, SIGNAL(guiLoadingFinished()), SLOT(bootstrapFinished()));
305
306 KisImageConfig config(false);
307
308#if !KRITA_QT_HAS_UPDATE_COMPRESSION_PATCH
309 m_d->canvasUpdateCompressor.setDelay(1000 / config.fpsLimit());
310 m_d->canvasUpdateCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);
311#endif
312
313 m_d->frameRenderStartCompressor.setDelay(1000 / config.fpsLimit());
314 m_d->frameRenderStartCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);
316}
317
319{
320 // a bit of duplication from slotConfigChanged()
321 KisConfig cfg(true);
322 m_d->lodPreferredInImage = cfg.levelOfDetailEnabled();
323 m_d->regionOfInterestMargin = KisImageConfig(true).animationCacheRegionOfInterestMargin();
324
325 createCanvas(cfg.useOpenGL());
326
327 setLodPreferredInCanvas(m_d->lodPreferredInImage);
328
329 connect(m_d->view->canvasController()->proxyObject, SIGNAL(effectiveZoomChanged(qreal)), SLOT(slotEffectiveZoomChanged(qreal)));
331
332 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
335
351 KisShapeController *kritaShapeController = static_cast<KisShapeController*>(shapeController()->documentBase());
352 connect(kritaShapeController, SIGNAL(selectionChanged()),
353 this, SLOT(slotSelectionChanged()));
354 connect(kritaShapeController, SIGNAL(selectionContentChanged()),
355 selectedShapesProxy(), SIGNAL(selectionContentChanged()));
356 connect(kritaShapeController, SIGNAL(currentLayerChanged(const KoShapeLayer*)),
357 selectedShapesProxy(), SIGNAL(currentLayerChanged(const KoShapeLayer*)));
358
359#if !KRITA_QT_HAS_UPDATE_COMPRESSION_PATCH
360 connect(&m_d->canvasUpdateCompressor, SIGNAL(timeout()), SLOT(slotDoCanvasUpdate()));
361#endif
362
363 connect(this, SIGNAL(sigCanvasCacheUpdated()), &m_d->frameRenderStartCompressor, SLOT(start()));
364 connect(&m_d->frameRenderStartCompressor, SIGNAL(timeout()), SLOT(updateCanvasProjection()));
365
366 connect(this, SIGNAL(sigContinueResizeImage(qint32,qint32)), SLOT(finishResizingImage(qint32,qint32)));
367
368 connect(&m_d->regionOfInterestUpdateCompressor, SIGNAL(timeout()), SLOT(slotUpdateRegionOfInterest()));
369 connect(&m_d->referencesBoundsUpdateCompressor, SIGNAL(timeout()), SLOT(slotUpdateReferencesBounds()));
370
371 connect(m_d->view->document(), SIGNAL(sigReferenceImagesChanged()), &m_d->referencesBoundsUpdateCompressor, SLOT(start()));
372
374
375 m_d->animationPlayer.reset(new KisCanvasAnimationState(this));
376}
377
379{
380 KisConfig cfg(true);
381
382 const bool shouldShowDebugOverlay =
385
386 if (shouldShowDebugOverlay && !decoration(KisFpsDecoration::idTag)) {
388
389 if (cfg.enableBrushSpeedLogging()) {
390 connect(KisStrokeSpeedMonitor::instance(), SIGNAL(sigStatsUpdated()), this, SLOT(updateCanvas()));
391 }
392 } else if (!shouldShowDebugOverlay && decoration(KisFpsDecoration::idTag)) {
393 m_d->canvasWidget->removeDecoration(KisFpsDecoration::idTag);
394 disconnect(KisStrokeSpeedMonitor::instance(), SIGNAL(sigStatsUpdated()), this, SLOT(updateCanvas()));
395 }
396}
397
399{
400 delete m_d;
401}
402
404{
405 if (m_d->popupPalette) {
406 m_d->popupPalette->setParent(widget->widget());
407 }
408
409 if (m_d->canvasWidget) {
415 widget->setDecorations(m_d->canvasWidget->decorations());
416
417 if(viewManager()) {
419 m_d->canvasWidget = widget;
421 } else {
422 m_d->canvasWidget = widget;
423 }
424 } else {
425 m_d->canvasWidget = widget;
426 }
427
428 if (!m_d->canvasWidget->decoration(INFINITY_DECORATION_ID)) {
429 KisInfinityManager *manager = new KisInfinityManager(m_d->view, this);
430 manager->setVisible(true);
431 m_d->canvasWidget->addDecoration(manager);
432 }
433
434 widget->widget()->setAutoFillBackground(false);
435 widget->widget()->setAttribute(Qt::WA_OpaquePaintEvent);
436 widget->widget()->setMouseTracking(true);
437 widget->widget()->setAcceptDrops(true);
438
440 if (controller && controller->canvas() == this) {
441 controller->changeCanvasWidget(widget->widget());
442 }
443
444
445#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
451 m_d->surfaceColorManager.reset();
452
453 QWindow *mainWindowNativeWindow = m_d->view->mainWindow()->windowHandle();
454 QWindow *nativeWindow = widget->widget()->windowHandle();
455
456 if (nativeWindow && nativeWindow != mainWindowNativeWindow) {
457 std::unique_ptr<KisSurfaceColorManagerInterface> iface(
458 KisPlatformPluginInterfaceFactory::instance()->createSurfaceColorManager(nativeWindow));
459
460 // if surfaceColorManagedByOS() is true, then interface is guaranteed to
461 // be present
463
464 if (iface) {
465 m_d->surfaceColorManager.reset(
466 new KisCanvasSurfaceColorSpaceManager(iface.release(),
467 m_d->multiSurfaceState->surfaceMode,
468 m_d->multiSurfaceState->multiConfig.options(),
469 this));
470
471 connect(m_d->surfaceColorManager.data(),
473 this,
475 }
476 } else {
477 qWarning() << "WARNING: created non-native Krita canvas on managed platform,"
478 << "its color space will be limited to sRGB";
479 }
480 }
481#endif
482}
483
485{
486 return m_d->currentCanvasIsOpenGL;
487}
488
490{
491 return KisOpenGL::FilterMode(m_d->openGLFilterMode);
492}
493
494void KisCanvas2::gridSize(QPointF *offset, QSizeF *spacing) const
495{
496 QTransform transform = coordinatesConverter()->imageToDocumentTransform();
497
498 const QPoint intSpacing = m_d->view->document()->gridConfig().spacing();
499 const QPoint intOffset = m_d->view->document()->gridConfig().offset();
500
501 QPointF size = transform.map(QPointF(intSpacing));
502 spacing->rwidth() = size.x();
503 spacing->rheight() = size.y();
504
505 *offset = transform.map(QPointF(intOffset));
506}
507
509{
510 return m_d->view->document()->gridConfig().snapToGrid();
511}
512
514{
515 return m_d->coordinatesConverter->rotationAngle();
516}
517
519{
520 return m_d->coordinatesConverter->xAxisMirrored();
521}
522
524{
525 return m_d->coordinatesConverter->yAxisMirrored();
526}
527
529{
530 KisImageSP image = this->image();
531 m_d->channelFlags = image->rootLayer()->channelFlags();
532
533 m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
534
536 m_d->canvasWidget->channelSelectionChanged(m_d->channelFlags);
538 image->unlock();
539}
540
542{
543 // This method exists to support flake-related operations
544 m_d->view->image()->undoAdapter()->addCommand(command);
545}
546
547void KisCanvas2::KisCanvas2Private::setActiveShapeManager(KoShapeManager *shapeManager)
548{
549 if (shapeManager != currentlyActiveShapeManager) {
550 currentlyActiveShapeManager = shapeManager;
551 selectedShapesProxy.setShapeManager(shapeManager);
552 }
553}
554
556{
558
559 // sanity check for consistency of the local shape manager
560 KIS_SAFE_ASSERT_RECOVER (localShapeManager == m_d->currentlyActiveShapeManager) {
562 }
563
565}
566
568{
569 return &m_d->selectedShapesProxy;
570}
571
573{
574 return &m_d->shapeManager;
575}
576
578{
579 KisNodeSP node = m_d->view->currentNode();
580 KoShapeManager *localShapeManager = fetchShapeManagerFromNode(node);
581
582 if (localShapeManager != m_d->currentlyActiveShapeManager) {
583 m_d->setActiveShapeManager(localShapeManager);
584 }
585
586 return localShapeManager;
587}
588
590{
591 return m_d->coordinatesConverter;
592}
593
595{
596 return m_d->coordinatesConverter;
597}
598
600{
601 return m_d->coordinatesConverter;
602}
603
605{
606 return m_d->view->globalInputManager();
607}
608
610{
611 return m_d->canvasWidget->widget();
612}
613
614const QWidget* KisCanvas2::canvasWidget() const
615{
616 return m_d->canvasWidget->widget();
617}
618
619
621{
623
624 KisImageWSP image = m_d->view->image();
625 if (image) {
626 if (!qFuzzyCompare(image->xRes(), image->yRes())) {
627 warnKrita << "WARNING: resolution of the image is anisotropic"
628 << ppVar(image->xRes())
629 << ppVar(image->yRes());
630 }
631
632 const qreal resolution = image->xRes();
633 unit.setFactor(resolution);
634 }
635
636 return unit;
637}
638
640{
641 return &m_d->toolProxy;
642}
643
645{
646 m_d->currentCanvasIsOpenGL = false;
647
648 m_d->multiSurfaceState =
649 m_d->multiSurfaceSetupManager.createInitializingConfig(false, m_d->currentScreenId(), m_d->proofingConfig);
650
651 KisQPainterCanvas * canvasWidget = new KisQPainterCanvas(this, m_d->coordinatesConverter, m_d->view);
652 m_d->prescaledProjection = new KisPrescaledProjection();
653 m_d->prescaledProjection->setCoordinatesConverter(m_d->coordinatesConverter);
654 m_d->prescaledProjection->setDisplayConfig(m_d->displayColorConverter.displayConfig());
655 m_d->prescaledProjection->setDisplayFilter(m_d->displayColorConverter.displayFilter());
656 canvasWidget->setPrescaledProjection(m_d->prescaledProjection);
658}
659
661{
662 KisConfig cfg(true);
663 m_d->openGLFilterMode = cfg.openGLFilteringMode();
664 m_d->currentCanvasIsOpenGL = true;
665
666 m_d->multiSurfaceState =
667 m_d->multiSurfaceSetupManager.createInitializingConfig(true, m_d->currentScreenId(), m_d->proofingConfig);
668
669 auto bitDepthMode =
670 cfg.effectiveCanvasSurfaceBitDepthMode(QSurfaceFormat::defaultFormat())
674
676 m_d->coordinatesConverter,
677 0,
678 m_d->view->image(),
679 m_d->multiSurfaceState->multiConfig.canvasDisplayConfig(),
680 m_d->displayColorConverter.displayFilter(),
681 bitDepthMode);
682 m_d->frameCache = KisAnimationFrameCache::getFrameCache(canvasWidget->openGLImageTextures());
683
685}
686
687void KisCanvas2::createCanvas(bool useOpenGL)
688{
689 // deinitialize previous canvas structures
690 m_d->prescaledProjection = 0;
691 m_d->frameCache = 0;
692
693 KisConfig cfg(true);
694
695 if (useOpenGL && !KisOpenGL::hasOpenGL()) {
696 warnKrita << "Tried to create OpenGL widget when system doesn't have OpenGL\n";
697 useOpenGL = false;
698 }
699
700 if (useOpenGL) {
702 if (cfg.canvasState() == "OPENGL_FAILED") {
703 // Creating the opengl canvas failed, fall back
704 warnKrita << "OpenGL Canvas initialization returned OPENGL_FAILED. Falling back to QPainter.";
706 }
707 } else {
709 }
710
711 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->multiSurfaceState);
712 m_d->displayColorConverter.setMultiSurfaceDisplayConfig(m_d->multiSurfaceState->multiConfig);
713
714 if (m_d->popupPalette) {
715 m_d->popupPalette->setParent(m_d->canvasWidget->widget());
716 }
717
718}
719
721{
722 KisImageSP image = m_d->view->image();
723
724 m_d->displayColorConverter.setImageColorSpace(image->colorSpace());
725 m_d->coordinatesConverter->setImage(image);
726 m_d->toolProxy.initializeImage(image);
727
728 connect(image, SIGNAL(sigImageUpdated(QRect)), SLOT(startUpdateCanvasProjection(QRect)), Qt::DirectConnection);
729 connect(image->signalRouter(), SIGNAL(sigNotifyBatchUpdateStarted()), SLOT(slotBeginUpdatesBatch()), Qt::DirectConnection);
730 connect(image->signalRouter(), SIGNAL(sigNotifyBatchUpdateEnded()), SLOT(slotEndUpdatesBatch()), Qt::DirectConnection);
731 connect(image->signalRouter(), SIGNAL(sigRequestLodPlanesSyncBlocked(bool)), SLOT(slotSetLodUpdatesBlocked(bool)), Qt::DirectConnection);
732
733 connect(image, SIGNAL(sigProofingConfigChanged()), SLOT(slotChangeProofingConfig()));
734 connect(image, SIGNAL(sigSizeChanged(QPointF,QPointF)), SLOT(startResizingImage()), Qt::DirectConnection);
735 connect(image->undoAdapter(), SIGNAL(selectionChanged()), SLOT(slotTrySwitchShapeManager()));
736
737 connect(image, SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), SLOT(slotImageColorSpaceChanged()));
738 connect(image, SIGNAL(sigProfileChanged(const KoColorProfile*)), SLOT(slotImageColorSpaceChanged()));
739
742}
743
745{
746 KisImageSP image = m_d->view->image();
747
756 disconnect(image.data(), 0, this, 0);
757 image->unlock();
758}
759
761{
762 KisImageWSP image = m_d->view->image();
763
764 if (!m_d->currentCanvasIsOpenGL) {
765 Q_ASSERT(m_d->prescaledProjection);
766 m_d->prescaledProjection->setImage(image);
767 }
768
770 setLodPreferredInCanvas(m_d->lodPreferredInImage);
771
772 Q_EMIT sigCanvasEngineChanged();
773}
774
775void KisCanvas2::resetCanvas(bool useOpenGL)
776{
777 // we cannot reset the canvas before it's created, but this method might be called,
778 // for instance when setting the monitor profile.
779 if (!m_d->canvasWidget) {
780 return;
781 }
782
783 KisConfig cfg(true);
784
785 const bool canvasHasNativeSurface = bool(m_d->canvasWidget->widget()->windowHandle());
786 const bool canvasNeedsNativeSurface =
789
790 bool needReset = (m_d->currentCanvasIsOpenGL != useOpenGL) ||
791 (m_d->currentCanvasIsOpenGL &&
792 m_d->openGLFilterMode != cfg.openGLFilteringMode()) ||
793 canvasHasNativeSurface != canvasNeedsNativeSurface;
794
795 if (needReset) {
796 createCanvas(useOpenGL);
798 slotEffectiveZoomChanged(m_d->coordinatesConverter->effectiveZoom());
799 }
801}
802
803void KisCanvas2::startUpdateInPatches(const QRect &imageRect)
804{
810 if (m_d->currentCanvasIsOpenGL) {
812 } else {
813 KisImageConfig imageConfig(true);
814 int patchWidth = imageConfig.updatePatchWidth();
815 int patchHeight = imageConfig.updatePatchHeight();
816
817 for (int y = 0; y < imageRect.height(); y += patchHeight) {
818 for (int x = 0; x < imageRect.width(); x += patchWidth) {
819 QRect patchRect(x, y, patchWidth, patchHeight);
821 }
822 }
823 }
824}
825
827{
828 m_d->displayColorConverter.setDisplayFilter(displayFilter);
829 KisImageSP image = this->image();
830
831 m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
832
834 m_d->canvasWidget->setDisplayFilter(displayFilter);
835 image->unlock();
836}
837
839{
840 return m_d->displayColorConverter.displayFilter();
841}
842
844{
845 KisImageSP image = this->image();
846
847 m_d->view->viewManager()->blockUntilOperationsFinishedForced(image);
848
849 m_d->displayColorConverter.setImageColorSpace(image->colorSpace());
850 m_d->channelFlags = image->rootLayer()->channelFlags();
851 m_d->canvasWidget->channelSelectionChanged(m_d->channelFlags);
852
853 // Not all color spaces are supported by soft-proofing, so update state
854 if (imageView()->softProofing()) {
856 }
857
859 m_d->canvasWidget->notifyImageColorSpaceChanged(image->colorSpace());
860 image->unlock();
861}
862
864{
865 return &m_d->displayColorConverter;
866}
867
876
878{
880 if (!baseConfig) {
881 baseConfig = KisImageConfig(true).defaultProofingconfiguration();
882 }
883 *m_d->proofingConfig = *baseConfig;
884
886}
887
889{
890 KoColorConversionTransformation::ConversionFlags displayFlags = m_d->proofingConfig->displayFlags;
891 displayFlags.setFlag(KoColorConversionTransformation::SoftProofing, false);
892
893 if (image()->colorSpace()->colorDepthId().id().contains("U")) {
894 displayFlags.setFlag(KoColorConversionTransformation::SoftProofing, imageView()->softProofing());
895 displayFlags.setFlag(KoColorConversionTransformation::GamutCheck, imageView()->gamutCheck());
896 }
897 m_d->proofingConfig->displayFlags = displayFlags;
898 m_d->proofingConfigUpdated = true;
899
900 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->multiSurfaceState);
901 auto newState = m_d->multiSurfaceSetupManager.onProofingChanged(*m_d->multiSurfaceState, m_d->proofingConfig);
902 m_d->assignChangedMultiSurfaceState(newState);
903}
904
910
912{
914 if (imageView()->softProofing()) {
916 }
917}
918
920{
921 if (image() && !image()->proofingConfiguration()) {
922 // global config should be updated only when
923 // the image doesn't have its own config
925 }
926}
927
929{
931 if (imageView()->softProofing()) {
933 }
934}
935
937{
938 m_d->proofingConfigUpdated = updated;
939}
940
942{
943 return m_d->proofingConfigUpdated;
944}
945
947{
948 return m_d->proofingConfig;
949}
950
952{
953 KisImageWSP image = this->image();
954 qint32 w = image->width();
955 qint32 h = image->height();
956
957 Q_EMIT sigContinueResizeImage(w, h);
958
959 QRect imageBounds(0, 0, w, h);
960 startUpdateInPatches(imageBounds);
961}
962
963void KisCanvas2::finishResizingImage(qint32 w, qint32 h)
964{
965 m_d->canvasWidget->finishResizingImage(w, h);
966}
967
969{
970 KisUpdateInfoSP info = m_d->canvasWidget->startUpdateCanvasProjection(rc);
971 if (m_d->projectionUpdatesCompressor.putUpdateInfo(info)) {
972 Q_EMIT sigCanvasCacheUpdated();
973 }
974}
975
977{
978 auto tryIssueCanvasUpdates = [this](const QRect &vRect) {
979 if (!m_d->isBatchUpdateActive) {
980 // TODO: Implement info->dirtyViewportRect() for KisOpenGLCanvas2 to avoid updating whole canvas
981 if (m_d->currentCanvasIsOpenGL) {
982 m_d->savedCanvasProjectionUpdateRect |= vRect;
983
984 // we already had a compression in frameRenderStartCompressor, so force the update directly
986 } else if (/* !m_d->currentCanvasIsOpenGL && */ !vRect.isEmpty()) {
987 m_d->savedCanvasProjectionUpdateRect |= m_d->coordinatesConverter->viewportToWidget(vRect).toAlignedRect();
988
989 // we already had a compression in frameRenderStartCompressor, so force the update directly
991 }
992 }
993 };
994
995 auto uploadData = [this, tryIssueCanvasUpdates](const QVector<KisUpdateInfoSP> &infoObjects) {
996 QVector<QRect> viewportRects = m_d->canvasWidget->updateCanvasProjection(infoObjects);
997 const QRect vRect = std::accumulate(viewportRects.constBegin(), viewportRects.constEnd(),
998 QRect(), std::bit_or<QRect>());
999
1000 tryIssueCanvasUpdates(vRect);
1001 };
1002
1003 bool shouldExplicitlyIssueUpdates = false;
1004
1005 QVector<KisUpdateInfoSP> infoObjects;
1006 KisUpdateInfoList originalInfoObjects;
1007 m_d->projectionUpdatesCompressor.takeUpdateInfo(originalInfoObjects);
1008
1009 for (auto it = originalInfoObjects.constBegin();
1010 it != originalInfoObjects.constEnd();
1011 ++it) {
1012
1013 KisUpdateInfoSP info = *it;
1014
1015 const KisMarkerUpdateInfo *batchInfo = dynamic_cast<const KisMarkerUpdateInfo*>(info.data());
1016 if (batchInfo) {
1017 if (!infoObjects.isEmpty()) {
1018 uploadData(infoObjects);
1019 infoObjects.clear();
1020 }
1021
1022 if (batchInfo->type() == KisMarkerUpdateInfo::StartBatch) {
1023 m_d->isBatchUpdateActive++;
1024 } else if (batchInfo->type() == KisMarkerUpdateInfo::EndBatch) {
1025 m_d->isBatchUpdateActive--;
1026 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->isBatchUpdateActive >= 0);
1027 if (m_d->isBatchUpdateActive == 0) {
1028 shouldExplicitlyIssueUpdates = true;
1029 }
1030 } else if (batchInfo->type() == KisMarkerUpdateInfo::BlockLodUpdates) {
1031 m_d->canvasWidget->setLodResetInProgress(true);
1032 } else if (batchInfo->type() == KisMarkerUpdateInfo::UnblockLodUpdates) {
1033 m_d->canvasWidget->setLodResetInProgress(false);
1034 shouldExplicitlyIssueUpdates = true;
1035 }
1036 } else {
1037 infoObjects << info;
1038 }
1039 }
1040
1041 if (!infoObjects.isEmpty()) {
1042 uploadData(infoObjects);
1043 } else if (shouldExplicitlyIssueUpdates) {
1044 tryIssueCanvasUpdates(m_d->coordinatesConverter->imageRectInImagePixels());
1045 }
1046}
1047
1049{
1050 KisUpdateInfoSP info =
1052 m_d->coordinatesConverter->imageRectInImagePixels());
1053 m_d->projectionUpdatesCompressor.putUpdateInfo(info);
1054 Q_EMIT sigCanvasCacheUpdated();
1055}
1056
1058{
1059 KisUpdateInfoSP info =
1061 m_d->coordinatesConverter->imageRectInImagePixels());
1062 m_d->projectionUpdatesCompressor.putUpdateInfo(info);
1063 Q_EMIT sigCanvasCacheUpdated();
1064}
1065
1067{
1068 KisUpdateInfoSP info =
1072 m_d->coordinatesConverter->imageRectInImagePixels());
1073 m_d->projectionUpdatesCompressor.putUpdateInfo(info);
1074 Q_EMIT sigCanvasCacheUpdated();
1075}
1076
1078{
1083#if !KRITA_QT_HAS_UPDATE_COMPRESSION_PATCH
1084 m_d->canvasUpdateCompressor.start();
1085#else
1087#endif
1088}
1089
1091{
1092
1093#if !KRITA_QT_HAS_UPDATE_COMPRESSION_PATCH
1099 if (m_d->canvasWidget->isBusy()) {
1100 // just restarting the timer
1101 m_d->canvasUpdateCompressor.start();
1102 return;
1103 }
1104#endif
1105
1106 QRect combinedUpdateRect = m_d->savedCanvasProjectionUpdateRect | m_d->savedOverlayUpdateRect;
1107 if (!combinedUpdateRect.isEmpty()) {
1108 // TODO: Remove this signal (only used by the old KisSketchView)
1109 Q_EMIT updateCanvasRequested(combinedUpdateRect);
1110
1111 if (wrapAroundViewingMode() && !m_d->savedCanvasProjectionUpdateRect.isEmpty()) {
1112 const QRect widgetRect = m_d->canvasWidget->widget()->rect();
1113 const QRect imageRect = m_d->coordinatesConverter->imageRectInImagePixels();
1114
1115 const QRect widgetRectInImagePixels =
1116 m_d->coordinatesConverter->widgetToImage(widgetRect).toAlignedRect();
1117
1118 const QRect rc = m_d->coordinatesConverter->widgetToImage(m_d->savedCanvasProjectionUpdateRect).toAlignedRect();
1119
1120 const QVector<QRect> updateRects =
1121 KisWrappedRect::multiplyWrappedRect(rc, imageRect, widgetRectInImagePixels, wrapAroundViewingModeAxis());
1122
1123 Q_FOREACH(const QRect &rc, updateRects) {
1124 const QRect widgetUpdateRect =
1125 m_d->coordinatesConverter->imageToWidget(rc).toAlignedRect() & widgetRect;
1126 m_d->canvasWidget->updateCanvasImage(widgetUpdateRect);
1127 }
1128 m_d->canvasWidget->updateCanvasDecorations(m_d->savedOverlayUpdateRect);
1129 } else {
1130 m_d->canvasWidget->updateCanvasImage(m_d->savedCanvasProjectionUpdateRect);
1131 m_d->canvasWidget->updateCanvasDecorations(m_d->savedOverlayUpdateRect);
1132 }
1133 } else if (m_d->updateSceneRequested) {
1134 m_d->canvasWidget->widget()->update();
1135 }
1136
1137 m_d->savedCanvasProjectionUpdateRect = QRect();
1138 m_d->savedOverlayUpdateRect = QRect();
1139 m_d->updateSceneRequested = false;
1140}
1141
1143{
1144 QRect rect = m_d->canvasWidget->widget()->rect();
1145 if (!rc.isEmpty()) {
1146 rect &= rc;
1147 if (rect.isEmpty()) {
1148 return;
1149 }
1150 }
1151 // We don't know if it's the canvas projection or the overlay that's
1152 // changed, so we update both.
1153 m_d->savedCanvasProjectionUpdateRect |= rect;
1154 m_d->savedOverlayUpdateRect |= rect;
1156}
1157
1162
1163QRect KisCanvas2::KisCanvas2Private::docUpdateRectToWidget(const QRectF &docRect)
1164{
1165 QRect widgetRect = coordinatesConverter->documentToWidget(docRect).toAlignedRect();
1166 widgetRect.adjust(-2, -2, 2, 2);
1167 return widgetRect & canvasWidget->widget()->rect();
1168}
1169
1170void KisCanvas2::updateCanvas(const QRectF& documentRect)
1171{
1172 // updateCanvas is called from tools, never from the projection
1173 // updates, so no need to prescale!
1174 QRect widgetRect = m_d->docUpdateRectToWidget(documentRect);
1175 if (!widgetRect.isEmpty()) {
1176 updateCanvasWidgetImpl(widgetRect);
1177 }
1178}
1179
1180void KisCanvas2::updateCanvasProjection(const QRectF &docRect)
1181{
1182 QRect widgetRect = m_d->docUpdateRectToWidget(docRect);
1183 if (!widgetRect.isEmpty()) {
1184 m_d->savedCanvasProjectionUpdateRect |= widgetRect;
1186 }
1187}
1188
1190{
1191 m_d->savedOverlayUpdateRect = m_d->canvasWidget->widget()->rect();
1193}
1194
1195void KisCanvas2::updateCanvasDecorations(const QRectF &docRect)
1196{
1197 QRect widgetRect = m_d->docUpdateRectToWidget(docRect);
1198 if (!widgetRect.isEmpty()) {
1199 m_d->savedOverlayUpdateRect |= widgetRect;
1201 }
1202}
1203
1205{
1206 QRect widgetRect = m_d->docUpdateRectToWidget(docRect);
1207 if (!widgetRect.isEmpty()) {
1208 updateCanvasToolOutlineWdg(widgetRect);
1209 }
1210}
1211
1212void KisCanvas2::updateCanvasToolOutlineWdg(const QRect &widgetRect)
1213{
1214 QRect rect = widgetRect & m_d->canvasWidget->widget()->rect();
1215 if (!rect.isEmpty()) {
1216 m_d->savedOverlayUpdateRect |= rect;
1217#ifdef HAVE_NO_QT_UPDATE_COMPRESSIO
1218 m_d->canvasUpdateCompressor.start();
1219#else
1221#endif
1222 }
1223}
1224
1226{
1227 m_d->updateSceneRequested = true;
1229}
1230
1232{
1234 m_d->view->disconnect(object);
1235}
1236
1238{
1239 Q_UNUSED(newZoom)
1240
1241
1242
1244}
1245
1246QRect KisCanvas2::regionOfInterest() const
1247{
1248 return m_d->regionOfInterest;
1249}
1250
1252{
1253 const QRect oldRegionOfInterest = m_d->regionOfInterest;
1254
1255 const qreal ratio = m_d->regionOfInterestMargin;
1256 const QRect proposedRoi = KisAlgebra2D::blowRect(m_d->coordinatesConverter->widgetRectInImagePixels(), ratio).toAlignedRect();
1257
1258 const QRect imageRect = m_d->coordinatesConverter->imageRectInImagePixels();
1259
1260 m_d->regionOfInterest = proposedRoi & imageRect;
1261
1262 if (m_d->regionOfInterest != oldRegionOfInterest) {
1263 Q_EMIT sigRegionOfInterestChanged(m_d->regionOfInterest);
1264 }
1265}
1266
1268{
1269 QRectF referencesRect;
1270 KisReferenceImagesLayerSP layer = m_d->view->document()->referenceImagesLayer();
1271 if (layer) {
1272 referencesRect = layer->boundingImageRect();
1273 }
1274
1275 m_d->view->canvasController()->syncOnReferencesChange(referencesRect);
1276}
1277
1279{
1280 m_d->renderingLimit = rc;
1281}
1282
1283QRect KisCanvas2::renderingLimit() const
1284{
1285 return m_d->renderingLimit;
1286}
1287
1289{
1290 return m_d->popupPalette;
1291}
1292
1294{
1295 KisNodeSP node = m_d->view->currentNode();
1296
1297 QPointer<KoShapeManager> newManager;
1298 newManager = fetchShapeManagerFromNode(node);
1299
1300 m_d->setActiveShapeManager(newManager);
1301}
1302
1304{
1305 KisImageSP image = this->image();
1306
1307 if (m_d->bootstrapLodBlocked || !m_d->lodIsSupported()) {
1309 } else {
1310 const qreal effectiveZoom = m_d->coordinatesConverter->effectiveZoom();
1311
1312 KisConfig cfg(true);
1313 const int maxLod = cfg.numMipmapLevels();
1314 const int lod = KisLodTransform::scaleToLod(effectiveZoom, maxLod);
1315 KisLodPreferences::PreferenceFlags flags = KisLodPreferences::LodSupported;
1316
1317 if (m_d->lodPreferredInImage) {
1319 }
1321 }
1322}
1323
1325{
1326 if (m_d->view) {
1327 return m_d->view->viewManager();
1328 }
1329 return 0;
1330}
1331
1333{
1334 return m_d->view;
1335}
1336
1338{
1339 return m_d->view->image();
1340
1341}
1342
1344{
1345 return m_d->view->image();
1346}
1347
1349{
1350 if (!m_d->currentCanvasIsOpenGL) {
1351 Q_ASSERT(m_d->prescaledProjection);
1352 auto state = KisCanvasState::fromConverter(*m_d->coordinatesConverter);
1353 m_d->prescaledProjection->notifyCanvasStateChanged(state);
1354 }
1355
1356 updateCanvas();
1357 m_d->regionOfInterestUpdateCompressor.start();
1358
1359 Q_EMIT sigCanvasStateChanged();
1360}
1361
1363{
1364 KisConfig cfg(true);
1365 m_d->regionOfInterestMargin = KisImageConfig(true).animationCacheRegionOfInterestMargin();
1366
1367 resetCanvas(cfg.useOpenGL());
1368
1369 QWidget *mainWindow = m_d->view->mainWindow();
1371
1372 QWidget *topLevelWidget = mainWindow->topLevelWidget();
1373 KIS_SAFE_ASSERT_RECOVER_RETURN(topLevelWidget);
1374
1375 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->multiSurfaceState);
1376 auto newState = m_d->multiSurfaceSetupManager.onConfigChanged(*m_d->multiSurfaceState,
1377 m_d->currentScreenId(),
1380 m_d->assignChangedMultiSurfaceState(newState);
1381
1383}
1384
1386{
1387 const int screenId = qApp->screens().indexOf(screen);
1388
1389 if (screenId < 0) {
1390 warnUI << "Failed to get screenNumber for updating display profile.";
1391 return;
1392 }
1393
1394 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->multiSurfaceState);
1395 auto newState = m_d->multiSurfaceSetupManager.onScreenChanged(*m_d->multiSurfaceState,
1396 screenId);
1397 m_d->assignChangedMultiSurfaceState(newState);
1398}
1399
1401{
1402 KisImageSP image = this->image();
1403 KisImageReadOnlyBarrierLock l(image);
1405}
1406
1407void KisCanvas2::KisCanvas2Private::assignChangedMultiSurfaceStateSkipCanvasSurface(const KisMultiSurfaceStateManager::State &newState)
1408{
1409 // the surface state is supposed to be initialized on canvas creation
1410 KIS_SAFE_ASSERT_RECOVER_RETURN(multiSurfaceState);
1411
1412 if (*multiSurfaceState == newState) return;
1413
1414 const KisMultiSurfaceStateManager::State oldState = *this->multiSurfaceState;
1415 this->multiSurfaceState = newState;
1416
1417 displayColorConverter.setMultiSurfaceDisplayConfig(newState.multiConfig);
1418
1419 if (oldState.multiConfig.canvasDisplayConfig() != newState.multiConfig.canvasDisplayConfig()) {
1420 KisImageSP image = view->image();
1421 KisImageReadOnlyBarrierLock l(image);
1422 canvasWidget->setDisplayConfig(multiSurfaceState->multiConfig.canvasDisplayConfig());
1423
1424 q->refetchDataFromImage();
1425
1426 // we changed the canvas conversion mode, so the canvas background color
1427 // has changed as well
1428 q->updateCanvas();
1429 }
1430}
1431
1432void KisCanvas2::KisCanvas2Private::assignChangedMultiSurfaceState(const KisMultiSurfaceStateManager::State &newState)
1433{
1434 assignChangedMultiSurfaceStateSkipCanvasSurface(newState);
1435
1436#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
1437
1438 if (surfaceColorManager) {
1439 surfaceColorManager->setDisplayConfigOptions(newState.surfaceMode, newState.multiConfig.options());
1440 }
1441
1442#endif
1443}
1444
1446{
1447#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
1448
1449 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->multiSurfaceState);
1450 if (m_d->multiSurfaceState->multiConfig.canvasDisplayConfig() == config) return;
1451
1452 if (m_d->multiSurfaceState->isCanvasOpenGL) {
1453 if (config.isHDR &&
1454 m_d->canvasWidget->currentBitDepthMode() < KisOpenGLCanvas2::BitDepthMode::Depth10Bit) {
1455
1456 const QString warningMessage = i18n(
1457 "WARNING: HDR mode was activated on surface working in 8-bit mode!\n"
1458 "Please activate 10-bit mode in Krita's Preferences dialog and restart "
1459 "Krita to avoid color banding!");
1460
1461 m_d->view->showFloatingMessage(warningMessage, koIcon("warning"), 7000, KisFloatingMessage::High);
1462 warnOpenGL.noquote() << QString(warningMessage).replace('\n', ' ');
1463 warnOpenGL << ppVar(QSurfaceFormat::defaultFormat());
1464 }
1465 }
1466
1467 auto newState = m_d->multiSurfaceSetupManager.onCanvasSurfaceFormatChanged(*m_d->multiSurfaceState, config);
1468 m_d->assignChangedMultiSurfaceStateSkipCanvasSurface(newState);
1469#endif
1470}
1471
1473{
1474 m_d->canvasWidget->addDecoration(deco);
1475}
1476
1478{
1479 return m_d->canvasWidget->decoration(id);
1480}
1481
1482
1484{
1491 return QPoint();
1492}
1493
1495{
1496 return m_d->coordinatesConverter->documentOffset();
1497}
1498
1500{
1501 m_d->popupPalette = new KisPopupPalette(viewManager(), m_d->coordinatesConverter, favoriteResourceManager, displayColorConverter()->displayRendererInterface(),
1502 m_d->canvasWidget->widget());
1503 connect(m_d->popupPalette, SIGNAL(zoomLevelChanged(int)), this, SLOT(slotPopupPaletteRequestedZoomChange(int)));
1504 connect(m_d->popupPalette, SIGNAL(sigUpdateCanvas()), this, SLOT(updateCanvas()));
1505 connect(m_d->view->mainWindow(), SIGNAL(themeChanged()), m_d->popupPalette, SLOT(slotUpdateIcons()));
1506}
1507
1509 m_d->view->canvasController()->setZoom(KoZoomMode::ZOOM_CONSTANT, (qreal)(zoom/100.0)); // 1.0 is 100% zoom
1510}
1511
1512void KisCanvas2::setCursor(const QCursor &cursor)
1513{
1514 canvasWidget()->setCursor(cursor);
1515}
1516
1518{
1519 return m_d->frameCache;
1520}
1521
1523{
1524 return m_d->animationPlayer.data();
1525}
1526
1528{
1529 KisShapeLayer* shapeLayer = dynamic_cast<KisShapeLayer*>(viewManager()->activeLayer().data());
1530 if (!shapeLayer) {
1531 return;
1532 }
1533 m_d->shapeManager.selection()->deselectAll();
1534 Q_FOREACH (KoShape* shape, shapeLayer->shapeManager()->selection()->selectedShapes()) {
1535 m_d->shapeManager.selection()->select(shape);
1536 }
1537}
1538
1540{
1541 KisCanvasDecorationSP infinityDecoration =
1542 m_d->canvasWidget->decoration(INFINITY_DECORATION_ID);
1543
1544 if (infinityDecoration) {
1545 infinityDecoration->setVisible(!value);
1546 }
1547
1548 m_d->canvasWidget->setWrapAroundViewingMode(value);
1549}
1550
1552{
1553 return m_d->canvasWidget->wrapAroundViewingMode();
1554}
1555
1557{
1558 m_d->canvasWidget->setWrapAroundViewingModeAxis(value);
1559 updateCanvas();
1560}
1561
1563{
1564 return m_d->canvasWidget->wrapAroundViewingModeAxis();
1565}
1566
1568{
1569 if (!m_d->bootstrapLodBlocked) return;
1570
1571 m_d->bootstrapLodBlocked = false;
1572 setLodPreferredInCanvas(m_d->lodPreferredInImage);
1573
1574 // Initialization of audio tracks is deferred until after canvas has been completely constructed.
1575 m_d->animationPlayer->setupAudioTracks();
1576}
1577
1579{
1580 if (!KisOpenGL::supportsLoD()) {
1581 qWarning() << "WARNING: Level of Detail functionality is available only with openGL + GLSL 1.3 support";
1582 }
1583
1584 m_d->lodPreferredInImage =
1585 value && m_d->lodIsSupported();
1586
1588
1589 KisConfig cfg(false);
1590 cfg.setLevelOfDetailEnabled(m_d->lodPreferredInImage);
1591}
1592
1594{
1595 return m_d->lodPreferredInImage;
1596}
1597
1599{
1600 KisCanvasDecorationSP deco = decoration("paintingAssistantsDecoration");
1601 return qobject_cast<KisPaintingAssistantsDecoration*>(deco.data());
1602}
1603
1605{
1606 KisCanvasDecorationSP deco = decoration("referenceImagesDecoration");
1607 return qobject_cast<KisReferenceImagesDecoration*>(deco.data());
1608}
1609
1611{
1612 return m_d->inputActionGroupsMaskInterface;
1613}
1614
1616{
1617#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
1618 QString report;
1619 QDebug str(&report);
1620
1621 if (m_d->canvasWidget) {
1622 str << "(canvas bit depth report)" << Qt::endl;
1623 str << Qt::endl;
1624 str.noquote().nospace() << m_d->canvasWidget->currentBitDepthUserReport();
1625 }
1626
1627 str << Qt::endl;
1628
1629 if (m_d->surfaceColorManager) {
1630 str.noquote().nospace() << QString("(canvas surface color manager)\n");
1631 str.noquote().nospace() << QString("\n");
1632 str.noquote().nospace() << m_d->surfaceColorManager->colorManagementReport();
1633 } else {
1634 str.noquote().nospace() << QString("Surface color management is not supported on this platform\n");
1635 }
1636
1637 return report;
1638#else
1639 return "Surface color management is disabled\n";
1640#endif
1641}
float value(const T *src, size_t ch)
@ AllActionGroup
WrapAroundAxis
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
virtual void setDecorations(const QList< KisCanvasDecorationSP > &)=0
virtual QWidget * widget()=0
static KisAnimationFrameCacheSP getFrameCache(KisOpenGLImageTexturesSP textures)
KisReferenceImagesDecorationSP referenceImagesDecoration() const
qreal rotationAngle() const
canvas rotation in degrees
KisSelectedShapesProxy selectedShapesProxy
void startUpdateInPatches(const QRect &imageRect)
bool effectiveLodAllowedInImage() const
void slotScreenChanged(QScreen *screen)
void setLodPreferredInCanvas(bool value)
KisPopupPalette * popupPalette
KisCanvas2Private *const m_d
KisCanvasAnimationState * animationState() const
void refetchDataFromImage()
QRect regionOfInterest
void slotGamutCheck()
void slotBeginUpdatesBatch()
QScopedPointer< KisCanvasAnimationState > animationPlayer
void updateCanvasToolOutlineDoc(const QRectF &docRect)
void initializeFpsDecoration()
bool proofingConfigUpdated
void assignChangedMultiSurfaceStateSkipCanvasSurface(const KisMultiSurfaceStateManager::State &newState)
void setFavoriteResourceManager(KisFavoriteResourceManager *favoriteResourceManager)
KoUnit unit() const override
KisExposureGammaCorrectionInterface * exposureGammaCorrectionInterface() const
QRect renderingLimit
void slotCanvasStateChanged()
void fetchProofingOptions()
fetchProofingOptions Get the options for softproofing, and apply the view-specific state without affe...
QPointer< KisView > view
void sigCanvasStateChanged()
KisDisplayColorConverter displayColorConverter
void sigContinueResizeImage(qint32 w, qint32 h)
void startResizingImage()
void setCursor(const QCursor &cursor) override
void gridSize(QPointF *offset, QSizeF *spacing) const override
bool xAxisMirrored() const
Bools indicating canvasmirroring.
void slotUpdateReferencesBounds()
void setDisplayFilter(QSharedPointer< KisDisplayFilter > displayFilter)
bool wrapAroundViewingMode() const
KisInputManager * globalInputManager() const
void slotEndUpdatesBatch()
KisAnimationFrameCacheSP frameCache
KisImageWSP currentImage() const
void slotSelectionChanged()
void setWrapAroundViewingMode(bool value)
QRect savedCanvasProjectionUpdateRect
void createQPainterCanvas()
std::optional< KisMultiSurfaceStateManager::State > multiSurfaceState
void resetCanvas(bool useOpenGL)
KisProofingConfigurationSP proofingConfig
KisCoordinatesConverter * coordinatesConverter
void bootstrapFinished()
void setProofingConfigUpdated(bool updated)
setProofingConfigUpdated This function is to set whether the proofing config is updated,...
QRect savedOverlayUpdateRect
KisImageWSP image() const
void addCommand(KUndo2Command *command) override
void updateProofingState()
KoShapeManager * localShapeManager() const
void initializeImage()
WrapAroundAxis wrapAroundViewingModeAxis() const
void addDecoration(KisCanvasDecorationSP deco)
KoShapeManager shapeManager
KisViewManager * viewManager() const
void slotSurfaceFormatChanged(const KisDisplayConfig &config)
QSharedPointer< CanvasInputActionGroupsMaskInterface > inputActionGroupsMaskInterface
bool canvasIsOpenGL() const override
void slotPopupPaletteRequestedZoomChange(int zoom)
~KisCanvas2() override
int currentScreenId() const
QPointer< KisView > imageView() const
void setRenderingLimit(const QRect &rc)
void createCanvas(bool useOpenGL)
QRect docUpdateRectToWidget(const QRectF &docRect)
QPointer< KoShapeManager > currentlyActiveShapeManager
void slotConfigChanged()
KisAbstractCanvasWidget * canvasWidget
void assignChangedMultiSurfaceState(const KisMultiSurfaceStateManager::State &newState)
KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResourceProvider *resourceManager, KisMainWindow *mainWindow, KisView *view, KoShapeControllerBase *sc)
bool lodPreferredInCanvas() const
void updateCanvasScene()
KisToolProxy toolProxy
void disconnectImage()
void requestCanvasUpdateMaybeCompressed()
void slotSoftProofing()
KoShapeManager * globalShapeManager() const
void updateCanvasProjection()
KisSignalCompressor referencesBoundsUpdateCompressor
KisCanvasDecorationSP decoration(const QString &id) const
KisCanvasUpdatesCompressor projectionUpdatesCompressor
QPoint documentOrigin() const override
void slotSetLodUpdatesBlocked(bool value)
void startUpdateCanvasProjection(const QRect &rc)
QPoint documentOffset() const
KisSignalCompressor canvasUpdateCompressor
void setCanvasWidget(KisAbstractCanvasWidget *widget)
KisPaintingAssistantsDecorationSP paintingAssistantsDecoration() const
void slotImageColorSpaceChanged()
void disconnectCanvasObserver(QObject *object) override
void updateCanvasDecorations()
void notifyLevelOfDetailChange()
void slotChangeGlobalProofingConfig()
void finishResizingImage(qint32 w, qint32 h)
bool yAxisMirrored() const
void slotChangeProofingConfig()
void slotDoCanvasUpdate()
KisProofingConfigurationSP proofingConfiguration() const
bool lodIsSupported() const
void connectCurrentCanvas()
void slotUpdateRegionOfInterest()
void updateCanvas()
Update the entire canvas area.
void setActiveShapeManager(KoShapeManager *shapeManager)
void updateCanvasWidgetImpl(const QRect &rc=QRect())
KisCanvas2Private(KisCanvas2 *parent, KisCoordinatesConverter *coordConverter, QPointer< KisView > view, KoCanvasResourceProvider *resourceManager)
void updateCanvasToolOutlineWdg(const QRect &widgetRect)
void createOpenGLCanvas()
void channelSelectionChanged()
KisMultiSurfaceStateManager multiSurfaceSetupManager
QString colorManagementReport() const
void sigCanvasEngineChanged()
void slotEffectiveZoomChanged(qreal newZoom)
void slotTrySwitchShapeManager()
KisSignalCompressor regionOfInterestUpdateCompressor
KisPrescaledProjectionSP prescaledProjection
const KoViewConverter * viewConverter() const override
void sigRegionOfInterestChanged(const QRect &roi)
QSharedPointer< KisDisplayFilter > displayFilter() const
QBitArray channelFlags
bool snapToGrid() const override
void sigCanvasCacheUpdated()
KisSignalCompressor frameRenderStartCompressor
void updateCanvasRequested(const QRect &rc)
void setWrapAroundViewingModeAxis(WrapAroundAxis value)
The KisCanvasAnimationState class stores all of the canvas-specific animation state.
virtual void setVisible(bool v)
static KisCanvasState fromConverter(const KisCoordinatesConverter &converter)
static KisConfigNotifier * instance()
int openGLFilteringMode(bool defaultValue=false) const
CanvasSurfaceBitDepthMode effectiveCanvasSurfaceBitDepthMode(const QSurfaceFormat &format) const
int numMipmapLevels(bool defaultValue=false) const
bool levelOfDetailEnabled(bool defaultValue=false) const
bool enableOpenGLFramerateLogging(bool defaultValue=false) const
CanvasSurfaceMode canvasSurfaceColorSpaceManagementMode(bool defaultValue=false) const
void setLevelOfDetailEnabled(bool value)
bool enableCanvasSurfaceColorSpaceManagement(bool defaultValue=false) const
bool enableBrushSpeedLogging(bool defaultValue=false) const
QString canvasState(bool defaultValue=false) const
bool useOpenGL(bool defaultValue=false) const
KisDisplayConfig This class keeps track of the color management configuration for image to display....
static Options optionsFromKisConfig(const KisConfig &cfg)
static const QString idTag
static KisImageConfigNotifier * instance()
void globalProofingConfigChanged()
int updatePatchWidth() const
KisProofingConfigurationSP defaultProofingconfiguration(bool requestDefault=false)
int updatePatchHeight() const
int fpsLimit(bool defaultValue=false) const
qreal animationCacheRegionOfInterestMargin(bool defaultValue=false) const
KisUndoAdapter * undoAdapter() const
void setLodPreferences(const KisLodPreferences &value)
KisGroupLayerSP rootLayer() const
const KoColorSpace * colorSpace() const
void unlock()
Definition kis_image.cc:805
void barrierLock(bool readOnly=false)
Wait until all the queued background jobs are completed and lock the image.
Definition kis_image.cc:756
qint32 width() const
void immediateLockForReadOnly()
Definition kis_image.cc:793
double xRes() const
double yRes() const
qint32 height() const
KisImageSignalRouter * signalRouter()
QRect bounds() const override
KisProofingConfigurationSP proofingConfiguration() const
proofingConfiguration
Central object to manage canvas input.
void removeTrackedCanvas(KisCanvas2 *canvas)
void addTrackedCanvas(KisCanvas2 *canvas)
static int scaleToLod(qreal scale, int maxLod)
Main window for Krita.
KisDisplayConfig canvasDisplayConfig() const
static bool hasOpenGL()
Check for OpenGL.
static bool supportsLoD()
@ HighQualityFiltering
Definition kis_opengl.h:37
@ TrilinearFilterMode
Definition kis_opengl.h:36
static KisPlatformPluginInterfaceFactory * instance()
The KisProofingConfiguration struct Little struct that stores the proofing configuration for a given ...
void sigRootSurfaceProfileChanged(const KoColorProfile *profile) const
KoShapeManager * shapeManager() const
KoShapeManager * shapeManager() const
static KisStrokeSpeedMonitor * instance()
KisLayerSP activeLayer()
Convenience method to get at the active layer.
KisInputManager * inputManager() const
Filters events and sends them to canvas actions.
KoSnapGuide * snapGuide
virtual void disconnectCanvasObserver(QObject *object)
QPointer< KoShapeController > shapeController
KoCanvasController * controller
KoCanvasController * canvasController() const
virtual KoCanvasBase * canvas() const
The KoSelectedShapesProxy class is a special interface of KoCanvasBase to have a stable connection to...
const QList< KoShape * > selectedShapes() const
KoSelection * selection
void overrideSnapStrategy(Strategy type, KoSnapStrategy *strategy)
@ Pixel
Definition KoUnit.h:82
void setFactor(qreal factor)
Definition KoUnit.h:122
@ ZOOM_CONSTANT
zoom x %
Definition KoZoomMode.h:24
static bool qFuzzyCompare(half p1, half p2)
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define warnKrita
Definition kis_debug.h:87
#define ppVar(var)
Definition kis_debug.h:155
#define warnOpenGL
Definition kis_debug.h:102
#define warnUI
Definition kis_debug.h:94
#define koIcon(name)
Use these macros for icons without any issues.
Definition kis_icon.h:25
static const QString INFINITY_DECORATION_ID
Rect blowRect(const Rect &rect, qreal coeff)
CanvasInputActionGroupsMaskInterface(KisCanvas2Private *canvasPrivateRef)
KisInputActionGroupsMask inputActionGroupsMask() const override
void setInputActionGroupsMask(KisInputActionGroupsMask mask) override
void sigDisplayConfigChanged(const KisDisplayConfig &config)
static KisDumbExposureGammaCorrectionInterface * instance()
QBitArray channelFlags
Definition kis_layer.cc:167
KisSelectionComponent * shapeSelection
bool hasShapeSelection() const
static QVector< QRect > multiplyWrappedRect(const QRect &rc, const QRect &wrapRect, const QRect &limitRect, WrapAroundAxis wrapAxis)