File indexing completed on 2024-05-19 04:29:09

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISASYNCANIMATIONRENDERERBASE_H
0008 #define KISASYNCANIMATIONRENDERERBASE_H
0009 
0010 #include <QObject>
0011 #include "kis_types.h"
0012 
0013 #include "kritaui_export.h"
0014 
0015 class KisRegion;
0016 class KisLockFrameGenerationLock;
0017 
0018 /**
0019  * KisAsyncAnimationRendererBase is a special class representing a
0020  * single worker thread inside KisAsyncAnimationRenderDialogBase. It connects
0021  * the specified image using correct Qt::DirectConnection connections and
0022  * reacts on them. On sigFrameReady() signal it calls frameCompletedCallback(),
0023  * so the derived class can fetch a frame from the image and process it. On
0024  * sigFrameCancelled() it calls frameCancelledCallback(). The derived class
0025  * should override these two methods to do the actual work.
0026  */
0027 
0028 class KRITAUI_EXPORT KisAsyncAnimationRendererBase : public QObject
0029 {
0030     Q_OBJECT
0031 
0032 public:
0033     enum Flag
0034     {
0035         None = 0x0,
0036         Cancellable = 0x1
0037     };
0038     Q_DECLARE_FLAGS(Flags, Flag)
0039 
0040     enum CancelReason {
0041         UserCancelled = 0,
0042         RenderingFailed,
0043         RenderingTimedOut
0044     };
0045     Q_ENUM(CancelReason)
0046 
0047 public:
0048     explicit KisAsyncAnimationRendererBase(QObject *parent = 0);
0049     virtual ~KisAsyncAnimationRendererBase();
0050 
0051     /**
0052      * Initiates the rendering of the frame \p frame on an image \p image.
0053      * Only \p regionOfInterest is regenerated. If \p regionOfInterest is
0054      * empty, then entire bounds of the image is regenerated.
0055      */
0056     void startFrameRegeneration(KisImageSP image, int frame, const KisRegion &regionOfInterest, Flags flags, KisLockFrameGenerationLock &&frameGenerationLock);
0057 
0058     /**
0059      * Convenience overload that regenerates the full image
0060      */
0061     void startFrameRegeneration(KisImageSP image, int frame, Flags flags, KisLockFrameGenerationLock &&frameGenerationLock);
0062 
0063     /**
0064      * @return true if the regeneration process is in progress
0065      */
0066     bool isActive() const;
0067 
0068 public Q_SLOTS:
0069     /**
0070      * @brief cancels current rendering operation
0071      *
0072      * After calling this slot requestedImage() becomes invalid.
0073      * @see requestedImage()
0074      */
0075     void cancelCurrentFrameRendering(CancelReason cancelReason);
0076 
0077 Q_SIGNALS:
0078     void sigFrameCompleted(int frame);
0079     void sigFrameCancelled(int frame, KisAsyncAnimationRendererBase::CancelReason cancelReason);
0080 
0081 private Q_SLOTS:
0082     void slotFrameRegenerationCancelled();
0083     void slotFrameRegenerationTimedOut();
0084     void slotFrameRegenerationFinished(int frame);
0085 
0086 protected Q_SLOTS:
0087     /**
0088      * Called by a derived class to continue processing of the frames
0089      */
0090     void notifyFrameCompleted(int frame);
0091 
0092     /**
0093      * Called by a derived class to cancel processing of the frames. After calling
0094      * this method, the dialog will stop processing the frames and close.
0095      */
0096     void notifyFrameCancelled(int frame, KisAsyncAnimationRendererBase::CancelReason cancelReason);
0097 
0098 protected:
0099     /**
0100      * @brief frameCompletedCallback is called by the renderer when
0101      *        a new frame becomes ready
0102      *
0103      * NOTE1: the callback is called from the context of a image
0104      *        worker thread! So it is asynchronous from the GUI thread.
0105      * NOTE2: in case of successful processing of the frame, the callback
0106      *        must issue some signal, connected to notifyFrameCompleted()
0107      *        via auto connection, to continue processing. Please do not
0108      *        call the method directly, because notifyFame*() slots should
0109      *        be called from the context of the GUI thread.
0110      * NOTE3: In case of failure, notifyFrameCancelled(). The same threading
0111      *        rules apply.
0112      */
0113     virtual void frameCompletedCallback(int frame, const KisRegion &requestedRegion) = 0;
0114 
0115     /**
0116      * @brief frameCancelledCallback is called when the rendering of
0117      *        the frame was cancelled.
0118      *
0119      * The rendering of the frame can be either cancelled by the image itself or
0120      * by receiving a timeout signal (10 seconds).
0121      *
0122      * NOTE: the slot is called in the GUI thread. Don't forget to call
0123      *       notifyFrameCancelled() in he end of your call.
0124      */
0125     virtual void frameCancelledCallback(int frame, CancelReason cancelReason) = 0;
0126 
0127 
0128     /**
0129      * Called by KisAsyncAnimationRendererBase when the processing has been completed
0130      * and the internal state of the populator should be cleared
0131      *
0132      * @param isCancelled tells if frame regeneration has failed to be regenerated
0133      */
0134     virtual void clearFrameRegenerationState(bool isCancelled);
0135 
0136 protected:
0137     /**
0138      * @return the image that for which the rendering was requested using
0139      * startFrameRegeneration(). Should be used by the derived classes only.
0140      *
0141      * Please note that requestedImage() will become null as soon as the user
0142      * cancels the processing. That happens in the GUI thread so
0143      * frameCompletedCallback() should be extremely careful when requesting the
0144      * value (check the shared pointer after fetching).
0145      */
0146     KisImageSP requestedImage() const;
0147 
0148 private:
0149     struct Private;
0150     const QScopedPointer<Private> m_d;
0151 };
0152 
0153 Q_DECLARE_OPERATORS_FOR_FLAGS(KisAsyncAnimationRendererBase::Flags)
0154 
0155 #endif // KISASYNCANIMATIONRENDERERBASE_H