Warning, file /office/calligra/libs/pigment/KoColorConversionCache.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * Copyright (C) 2007 Cyrille Berger <cberger@cberger.net>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "KoColorConversionCache.h"
0021 
0022 #include <QHash>
0023 #include <QList>
0024 #include <QMutex>
0025 #include <QThreadStorage>
0026 
0027 #include <KoColorSpace.h>
0028 
0029 struct KoColorConversionCacheKey {
0030 
0031     KoColorConversionCacheKey(const KoColorSpace* _src,
0032                               const KoColorSpace* _dst,
0033                               KoColorConversionTransformation::Intent _renderingIntent,
0034                               KoColorConversionTransformation::ConversionFlags _conversionFlags)
0035         : src(_src)
0036         , dst(_dst)
0037         , renderingIntent(_renderingIntent)
0038         , conversionFlags(_conversionFlags)
0039     {
0040     }
0041 
0042     bool operator==(const KoColorConversionCacheKey& rhs) const {
0043         return (*src == *(rhs.src)) && (*dst == *(rhs.dst))
0044                 && (renderingIntent == rhs.renderingIntent)
0045                 && (conversionFlags == rhs.conversionFlags);
0046     }
0047 
0048     const KoColorSpace* src;
0049     const KoColorSpace* dst;
0050     KoColorConversionTransformation::Intent renderingIntent;
0051     KoColorConversionTransformation::ConversionFlags conversionFlags;
0052 };
0053 
0054 uint qHash(const KoColorConversionCacheKey& key)
0055 {
0056     return qHash(key.src) + qHash(key.dst) + qHash(key.renderingIntent) + qHash(key.conversionFlags);
0057 }
0058 
0059 struct KoColorConversionCache::CachedTransformation {
0060 
0061     CachedTransformation(KoColorConversionTransformation* _transfo)
0062         : transfo(_transfo), use(0)
0063     {}
0064 
0065     ~CachedTransformation() {
0066         delete transfo;
0067     }
0068 
0069     bool available() {
0070         return use == 0;
0071     }
0072 
0073     KoColorConversionTransformation* transfo;
0074     int use;
0075 };
0076 
0077 typedef QPair<KoColorConversionCacheKey, KoCachedColorConversionTransformation> FastPathCacheItem;
0078 
0079 struct KoColorConversionCache::Private {
0080     QMultiHash< KoColorConversionCacheKey, CachedTransformation*> cache;
0081     QMutex cacheMutex;
0082 
0083     QThreadStorage<FastPathCacheItem*> fastStorage;
0084 };
0085 
0086 
0087 KoColorConversionCache::KoColorConversionCache() : d(new Private)
0088 {
0089 }
0090 
0091 KoColorConversionCache::~KoColorConversionCache()
0092 {
0093     foreach(CachedTransformation* transfo, d->cache) {
0094         delete transfo;
0095     }
0096     delete d;
0097 }
0098 
0099 KoCachedColorConversionTransformation KoColorConversionCache::cachedConverter(const KoColorSpace* src,
0100                                                                               const KoColorSpace* dst,
0101                                                                               KoColorConversionTransformation::Intent _renderingIntent,
0102                                                                               KoColorConversionTransformation::ConversionFlags _conversionFlags)
0103 {
0104     KoColorConversionCacheKey key(src, dst, _renderingIntent, _conversionFlags);
0105 
0106     FastPathCacheItem *cacheItem =
0107         d->fastStorage.localData();
0108 
0109     if (cacheItem) {
0110         if (cacheItem->first == key) {
0111             return cacheItem->second;
0112         }
0113     }
0114 
0115     cacheItem = 0;
0116 
0117     QMutexLocker lock(&d->cacheMutex);
0118     QList< CachedTransformation* > cachedTransfos = d->cache.values(key);
0119     if (cachedTransfos.size() != 0) {
0120         foreach(CachedTransformation* ct, cachedTransfos) {
0121             if (ct->available()) {
0122                 ct->transfo->setSrcColorSpace(src);
0123                 ct->transfo->setDstColorSpace(dst);
0124 
0125                 cacheItem = new FastPathCacheItem(key, KoCachedColorConversionTransformation(this, ct));
0126                 break;
0127             }
0128         }
0129     }
0130     if (!cacheItem) {
0131         KoColorConversionTransformation* transfo = src->createColorConverter(dst, _renderingIntent, _conversionFlags);
0132         CachedTransformation* ct = new CachedTransformation(transfo);
0133         d->cache.insert(key, ct);
0134         cacheItem = new FastPathCacheItem(key, KoCachedColorConversionTransformation(this, ct));
0135     }
0136 
0137     d->fastStorage.setLocalData(cacheItem);
0138     return cacheItem->second;
0139 }
0140 
0141 void KoColorConversionCache::colorSpaceIsDestroyed(const KoColorSpace* cs)
0142 {
0143     d->fastStorage.setLocalData(0);
0144 
0145     QMutexLocker lock(&d->cacheMutex);
0146     QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator endIt = d->cache.end();
0147     for (QMultiHash< KoColorConversionCacheKey, CachedTransformation*>::iterator it = d->cache.begin(); it != endIt;) {
0148         if (it.key().src == cs || it.key().dst == cs) {
0149             Q_ASSERT(it.value()->available()); // 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
0150             delete it.value();
0151             it = d->cache.erase(it);
0152         } else {
0153             ++it;
0154         }
0155     }
0156 }
0157 
0158 //--------- KoCachedColorConversionTransformation ----------//
0159 
0160 struct KoCachedColorConversionTransformation::Private {
0161     KoColorConversionCache* cache;
0162     KoColorConversionCache::CachedTransformation* transfo;
0163 };
0164 
0165 
0166 KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(KoColorConversionCache* cache, KoColorConversionCache::CachedTransformation* transfo) : d(new Private)
0167 {
0168     Q_ASSERT(transfo->available());
0169     d->cache = cache;
0170     d->transfo = transfo;
0171     d->transfo->use++;
0172 }
0173 
0174 KoCachedColorConversionTransformation::KoCachedColorConversionTransformation(const KoCachedColorConversionTransformation& rhs) : d(new Private(*rhs.d))
0175 {
0176     d->transfo->use++;
0177 }
0178 
0179 KoCachedColorConversionTransformation::~KoCachedColorConversionTransformation()
0180 {
0181     d->transfo->use--;
0182     Q_ASSERT(d->transfo->use >= 0);
0183     delete d;
0184 }
0185 
0186 const KoColorConversionTransformation* KoCachedColorConversionTransformation::transformation() const
0187 {
0188     return d->transfo->transfo;
0189 }
0190