File indexing completed on 2024-05-12 15:59:31

0001 /*
0002  * SPDX-FileCopyrightText: 2007 Cyrille Berger <cberger@cberger.net>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "KoColorConversionCache.h"
0008 
0009 #include <QHash>
0010 #include <QList>
0011 #include <QMutex>
0012 #include <QThreadStorage>
0013 
0014 #include <KoColorSpace.h>
0015 
0016 struct KoColorConversionCacheKey {
0017 
0018     KoColorConversionCacheKey(const KoColorSpace* _src,
0019                               const KoColorSpace* _dst,
0020                               KoColorConversionTransformation::Intent _renderingIntent,
0021                               KoColorConversionTransformation::ConversionFlags _conversionFlags)
0022         : src(_src)
0023         , dst(_dst)
0024         , renderingIntent(_renderingIntent)
0025         , conversionFlags(_conversionFlags)
0026     {
0027     }
0028 
0029     bool operator==(const KoColorConversionCacheKey& rhs) const {
0030         return (*src == *(rhs.src)) && (*dst == *(rhs.dst))
0031                 && (renderingIntent == rhs.renderingIntent)
0032                 && (conversionFlags == rhs.conversionFlags);
0033     }
0034 
0035     const KoColorSpace* src;
0036     const KoColorSpace* dst;
0037     KoColorConversionTransformation::Intent renderingIntent;
0038     KoColorConversionTransformation::ConversionFlags conversionFlags;
0039 };
0040 
0041 uint qHash(const KoColorConversionCacheKey& key)
0042 {
0043     return qHash(key.src) + qHash(key.dst) + qHash(key.renderingIntent) + qHash(key.conversionFlags);
0044 }
0045 
0046 struct KoColorConversionCache::CachedTransformation {
0047 
0048     CachedTransformation(KoColorConversionTransformation* _transfo)
0049         : transfo(_transfo), use(0)
0050     {}
0051 
0052     ~CachedTransformation() {
0053         delete transfo;
0054     }
0055 
0056     bool isNotInUse() {
0057         return !use;
0058     }
0059 
0060     KoColorConversionTransformation* transfo;
0061     QAtomicInt use;
0062 };
0063 
0064 typedef QPair<KoColorConversionCacheKey, KoCachedColorConversionTransformation> FastPathCacheItem;
0065 
0066 struct KoColorConversionCache::Private {
0067     QMultiHash< KoColorConversionCacheKey, CachedTransformation*> cache;
0068     QMutex cacheMutex;
0069 
0070     QThreadStorage<FastPathCacheItem*> fastStorage;
0071 };
0072 
0073 
0074 KoColorConversionCache::KoColorConversionCache() : d(new Private)
0075 {
0076 }
0077 
0078 KoColorConversionCache::~KoColorConversionCache()
0079 {
0080     Q_FOREACH (CachedTransformation* transfo, d->cache) {
0081         delete transfo;
0082     }
0083     delete d;
0084 }
0085 
0086 KoCachedColorConversionTransformation KoColorConversionCache::cachedConverter(const KoColorSpace* src,
0087                                                                               const KoColorSpace* dst,
0088                                                                               KoColorConversionTransformation::Intent _renderingIntent,
0089                                                                               KoColorConversionTransformation::ConversionFlags _conversionFlags)
0090 {
0091     KoColorConversionCacheKey key(src, dst, _renderingIntent, _conversionFlags);
0092 
0093     FastPathCacheItem *cacheItem =
0094         d->fastStorage.localData();
0095 
0096     if (cacheItem) {
0097         if (cacheItem->first == key) {
0098             return cacheItem->second;
0099         }
0100     }
0101 
0102     cacheItem = 0;
0103 
0104     QMutexLocker lock(&d->cacheMutex);
0105     QList< CachedTransformation* > cachedTransfos = d->cache.values(key);
0106     if (cachedTransfos.size() != 0) {
0107         Q_FOREACH (CachedTransformation* ct, cachedTransfos) {
0108             ct->transfo->setSrcColorSpace(src);
0109             ct->transfo->setDstColorSpace(dst);
0110 
0111             cacheItem = new FastPathCacheItem(key, KoCachedColorConversionTransformation(ct));
0112             break;
0113         }
0114     }
0115     if (!cacheItem) {
0116         KoColorConversionTransformation* transfo = src->createColorConverter(dst, _renderingIntent, _conversionFlags);
0117         CachedTransformation* ct = new CachedTransformation(transfo);
0118         d->cache.insert(key, ct);
0119         cacheItem = new FastPathCacheItem(key, KoCachedColorConversionTransformation(ct));
0120     }
0121 
0122     d->fastStorage.setLocalData(cacheItem);
0123     return cacheItem->second;
0124 }
0125 
0126 void KoColorConversionCache::colorSpaceIsDestroyed(const KoColorSpace* cs)
0127 {
0128     d->fastStorage.setLocalData(0);
0129 
0130     QMutexLocker lock(&d->cacheMutex);
0131     QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator endIt = d->cache.end();
0132     for (QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator it = d->cache.begin(); it != endIt;) {
0133         if (it.key().src == cs || it.key().dst == cs) {
0134             Q_ASSERT(it.value()->isNotInUse()); // That's terribely evil, if that assert fails, that means that someone is using a color transformation with a color space which is currently being deleted
0135             delete it.value();
0136             it = d->cache.erase(it);
0137         } else {
0138             ++it;
0139         }
0140     }
0141 }
0142 
0143 //--------- KoCachedColorConversionTransformation ----------//
0144 
0145 KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(KoColorConversionCache::CachedTransformation* transfo)
0146     : m_transfo(transfo)
0147 {
0148     m_transfo = transfo;
0149     m_transfo->use.ref();
0150 }
0151 
0152 KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(const KoCachedColorConversionTransformation& rhs)
0153     : m_transfo(rhs.m_transfo)
0154 {
0155     m_transfo->use.ref();
0156 }
0157 
0158 KoCachedColorConversionTransformation::~KoCachedColorConversionTransformation()
0159 {
0160     Q_ASSERT(m_transfo->use > 0);
0161     m_transfo->use.deref();
0162 }
0163 
0164 const KoColorConversionTransformation* KoCachedColorConversionTransformation::transformation() const
0165 {
0166     return m_transfo->transfo;
0167 }
0168