1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #define Q_TEST_QPIXMAPCACHE
41 #include "qpixmapcache.h"
42 #include "qobject.h"
43 #include "qdebug.h"
44 #include "qpixmapcache_p.h"
45 #include "qthread.h"
46 #include "qcoreapplication.h"
47 
48 QT_BEGIN_NAMESPACE
49 
50 /*!
51     \class QPixmapCache
52     \inmodule QtGui
53 
54     \brief The QPixmapCache class provides an application-wide cache for pixmaps.
55 
56     This class is a tool for optimized drawing with QPixmap. You can
57     use it to store temporary pixmaps that are expensive to generate
58     without using more storage space than cacheLimit(). Use insert()
59     to insert pixmaps, find() to find them, and clear() to empty the
60     cache.
61 
62     QPixmapCache contains no member data, only static functions to
63     access the global pixmap cache. It creates an internal QCache
64     object for caching the pixmaps.
65 
66     The cache associates a pixmap with a user-provided string as a key,
67     or with a QPixmapCache::Key that the cache generates.
68     Using QPixmapCache::Key for keys is faster than using strings. The string API is
69     very convenient for complex keys but the QPixmapCache::Key API will be very
70     efficient and convenient for a one-to-one object-to-pixmap mapping - in
71     this case, you can store the keys as members of an object.
72 
73     If two pixmaps are inserted into the cache using equal keys then the
74     last pixmap will replace the first pixmap in the cache. This follows the
75     behavior of the QHash and QCache classes.
76 
77     The cache becomes full when the total size of all pixmaps in the
78     cache exceeds cacheLimit(). The initial cache limit is 10240 KB (10 MB);
79     you can change this by calling setCacheLimit() with the required value.
80     A pixmap takes roughly (\e{width} * \e{height} * \e{depth})/8 bytes of
81     memory.
82 
83     The \e{Qt Quarterly} article
84     \l{http://doc.qt.io/archives/qq/qq12-qpixmapcache.html}{Optimizing
85     with QPixmapCache} explains how to use QPixmapCache to speed up
86     applications by caching the results of painting.
87 
88     \note QPixmapCache is only usable from the application's main thread.
89     Access from other threads will be ignored and return failure.
90 
91     \sa QCache, QPixmap
92 */
93 
94 static const int cache_limit_default = 10240; // 10 MB cache limit
95 
cost(const QPixmap & pixmap)96 static inline int cost(const QPixmap &pixmap)
97 {
98     // make sure to do a 64bit calculation
99     const qint64 costKb = static_cast<qint64>(pixmap.width()) *
100             pixmap.height() * pixmap.depth() / (8 * 1024);
101     const qint64 costMax = std::numeric_limits<int>::max();
102     // a small pixmap should have at least a cost of 1(kb)
103     return static_cast<int>(qBound(1LL, costKb, costMax));
104 }
105 
qt_pixmapcache_thread_test()106 static inline bool qt_pixmapcache_thread_test()
107 {
108     if (Q_LIKELY(QCoreApplication::instance() && QThread::currentThread() == QCoreApplication::instance()->thread()))
109         return true;
110 
111     return false;
112 }
113 
114 /*!
115     \class QPixmapCache::Key
116     \brief The QPixmapCache::Key class can be used for efficient access
117     to the QPixmapCache.
118     \inmodule QtGui
119     \since 4.6
120 
121     Use QPixmapCache::insert() to receive an instance of Key generated
122     by the pixmap cache. You can store the key in your own objects for
123     a very efficient one-to-one object-to-pixmap mapping.
124 */
125 
126 /*!
127     Constructs an empty Key object.
128 */
Key()129 QPixmapCache::Key::Key() : d(nullptr)
130 {
131 }
132 
133 /*!
134    \internal
135     Constructs a copy of \a other.
136 */
Key(const Key & other)137 QPixmapCache::Key::Key(const Key &other)
138 {
139     if (other.d)
140         ++(other.d->ref);
141     d = other.d;
142 }
143 
144 /*!
145     Destroys the key.
146 */
~Key()147 QPixmapCache::Key::~Key()
148 {
149     if (d && --(d->ref) == 0)
150         delete d;
151 }
152 
153 /*!
154     \internal
155 
156     Returns \c true if this key is the same as the given \a key; otherwise returns
157     false.
158 */
operator ==(const Key & key) const159 bool QPixmapCache::Key::operator ==(const Key &key) const
160 {
161     return (d == key.d);
162 }
163 
164 /*!
165     \fn bool QPixmapCache::Key::operator !=(const Key &key) const
166     \internal
167 */
168 
169 /*!
170     \fn QPixmapCache::Key::Key(Key &&)
171     \internal
172     \since 5.6
173 */
174 
175 /*!
176     \fn QPixmapCache::Key &QPixmapCache::Key::operator=(Key &&)
177     \internal
178     \since 5.6
179 */
180 
181 /*!
182     \fn void QPixmapCache::Key::swap(Key &)
183     \internal
184     \since 5.6
185 */
186 
187 /*!
188     Returns \c true if there is a cached pixmap associated with this key.
189     Otherwise, if pixmap was flushed, the key is no longer valid.
190     \since 5.7
191 */
isValid() const192 bool QPixmapCache::Key::isValid() const noexcept
193 {
194     return d && d->isValid;
195 }
196 
197 /*!
198     \internal
199 */
operator =(const Key & other)200 QPixmapCache::Key &QPixmapCache::Key::operator =(const Key &other)
201 {
202     if (d != other.d) {
203         if (other.d)
204             ++(other.d->ref);
205         if (d && --(d->ref) == 0)
206             delete d;
207         d = other.d;
208     }
209     return *this;
210 }
211 
212 class QPMCache : public QObject, public QCache<QPixmapCache::Key, QPixmapCacheEntry>
213 {
214     Q_OBJECT
215 public:
216     QPMCache();
217     ~QPMCache();
218 
219     void timerEvent(QTimerEvent *) override;
220     bool insert(const QString& key, const QPixmap &pixmap, int cost);
221     QPixmapCache::Key insert(const QPixmap &pixmap, int cost);
222     bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost);
223     bool remove(const QString &key);
224     bool remove(const QPixmapCache::Key &key);
225 
226     void resizeKeyArray(int size);
227     QPixmapCache::Key createKey();
228     void releaseKey(const QPixmapCache::Key &key);
229     void clear();
230 
231     QPixmap *object(const QString &key) const;
232     QPixmap *object(const QPixmapCache::Key &key) const;
233 
get(const QPixmapCache::Key & key)234     static inline QPixmapCache::KeyData *get(const QPixmapCache::Key &key)
235     {return key.d;}
236 
237     static QPixmapCache::KeyData* getKeyData(QPixmapCache::Key *key);
238 
239     bool flushDetachedPixmaps(bool nt);
240 
241 private:
242     enum { soon_time = 10000, flush_time = 30000 };
243     int *keyArray;
244     int theid;
245     int ps;
246     int keyArraySize;
247     int freeKey;
248     QHash<QString, QPixmapCache::Key> cacheKeys;
249     bool t;
250 };
251 
252 QT_BEGIN_INCLUDE_NAMESPACE
253 #include "qpixmapcache.moc"
254 QT_END_INCLUDE_NAMESPACE
255 
qHash(const QPixmapCache::Key & k)256 uint qHash(const QPixmapCache::Key &k)
257 {
258     return qHash(QPMCache::get(k)->key);
259 }
260 
QPMCache()261 QPMCache::QPMCache()
262     : QObject(nullptr),
263       QCache<QPixmapCache::Key, QPixmapCacheEntry>(cache_limit_default),
264       keyArray(nullptr), theid(0), ps(0), keyArraySize(0), freeKey(0), t(false)
265 {
266 }
~QPMCache()267 QPMCache::~QPMCache()
268 {
269     clear();
270     free(keyArray);
271 }
272 
273 /*
274   This is supposed to cut the cache size down by about 25% in a
275   minute once the application becomes idle, to let any inserted pixmap
276   remain in the cache for some time before it becomes a candidate for
277   cleaning-up, and to not cut down the size of the cache while the
278   cache is in active use.
279 
280   When the last detached pixmap has been deleted from the cache, kill the
281   timer so Qt won't keep the CPU from going into sleep mode. Currently
282   the timer is not restarted when the pixmap becomes unused, but it does
283   restart once something else is added (i.e. the cache space is actually needed).
284 
285   Returns \c true if any were removed.
286 */
flushDetachedPixmaps(bool nt)287 bool QPMCache::flushDetachedPixmaps(bool nt)
288 {
289     int mc = maxCost();
290     setMaxCost(nt ? totalCost() * 3 / 4 : totalCost() -1);
291     setMaxCost(mc);
292     ps = totalCost();
293 
294     bool any = false;
295     QHash<QString, QPixmapCache::Key>::iterator it = cacheKeys.begin();
296     while (it != cacheKeys.end()) {
297         if (!contains(it.value())) {
298             releaseKey(it.value());
299             it = cacheKeys.erase(it);
300             any = true;
301         } else {
302             ++it;
303         }
304     }
305 
306     return any;
307 }
308 
timerEvent(QTimerEvent *)309 void QPMCache::timerEvent(QTimerEvent *)
310 {
311     bool nt = totalCost() == ps;
312     if (!flushDetachedPixmaps(nt)) {
313         killTimer(theid);
314         theid = 0;
315     } else if (nt != t) {
316         killTimer(theid);
317         theid = startTimer(nt ? soon_time : flush_time);
318         t = nt;
319     }
320 }
321 
322 
object(const QString & key) const323 QPixmap *QPMCache::object(const QString &key) const
324 {
325     QPixmapCache::Key cacheKey = cacheKeys.value(key);
326     if (!cacheKey.d || !cacheKey.d->isValid) {
327         const_cast<QPMCache *>(this)->cacheKeys.remove(key);
328         return nullptr;
329     }
330     QPixmap *ptr = QCache<QPixmapCache::Key, QPixmapCacheEntry>::object(cacheKey);
331      //We didn't find the pixmap in the cache, the key is not valid anymore
332     if (!ptr) {
333         const_cast<QPMCache *>(this)->cacheKeys.remove(key);
334     }
335     return ptr;
336 }
337 
object(const QPixmapCache::Key & key) const338 QPixmap *QPMCache::object(const QPixmapCache::Key &key) const
339 {
340     Q_ASSERT(key.d->isValid);
341     QPixmap *ptr = QCache<QPixmapCache::Key, QPixmapCacheEntry>::object(key);
342     //We didn't find the pixmap in the cache, the key is not valid anymore
343     if (!ptr)
344         const_cast<QPMCache *>(this)->releaseKey(key);
345     return ptr;
346 }
347 
insert(const QString & key,const QPixmap & pixmap,int cost)348 bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost)
349 {
350     QPixmapCache::Key &cacheKey = cacheKeys[key];
351     //If for the same key we add already a pixmap we should delete it
352     if (cacheKey.d)
353         QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(cacheKey);
354 
355     //we create a new key the old one has been removed
356     cacheKey = createKey();
357 
358     bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
359     if (success) {
360         if (!theid) {
361             theid = startTimer(flush_time);
362             t = false;
363         }
364     } else {
365         //Insertion failed we released the new allocated key
366         cacheKeys.remove(key);
367     }
368     return success;
369 }
370 
insert(const QPixmap & pixmap,int cost)371 QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost)
372 {
373     QPixmapCache::Key cacheKey = createKey();
374     bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
375     if (success) {
376         if (!theid) {
377             theid = startTimer(flush_time);
378             t = false;
379         }
380     }
381     return cacheKey;
382 }
383 
replace(const QPixmapCache::Key & key,const QPixmap & pixmap,int cost)384 bool QPMCache::replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost)
385 {
386     Q_ASSERT(key.d->isValid);
387     //If for the same key we had already an entry so we should delete the pixmap and use the new one
388     QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(key);
389 
390     QPixmapCache::Key cacheKey = createKey();
391 
392     bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
393     if (success) {
394         if(!theid) {
395             theid = startTimer(flush_time);
396             t = false;
397         }
398         const_cast<QPixmapCache::Key&>(key) = cacheKey;
399     }
400     return success;
401 }
402 
remove(const QString & key)403 bool QPMCache::remove(const QString &key)
404 {
405     auto cacheKey = cacheKeys.constFind(key);
406     //The key was not in the cache
407     if (cacheKey == cacheKeys.constEnd())
408         return false;
409     const bool result = QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(cacheKey.value());
410     cacheKeys.erase(cacheKey);
411     return result;
412 }
413 
remove(const QPixmapCache::Key & key)414 bool QPMCache::remove(const QPixmapCache::Key &key)
415 {
416     return QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(key);
417 }
418 
resizeKeyArray(int size)419 void QPMCache::resizeKeyArray(int size)
420 {
421     if (size <= keyArraySize || size == 0)
422         return;
423     keyArray = q_check_ptr(reinterpret_cast<int *>(realloc(keyArray,
424                     size * sizeof(int))));
425     for (int i = keyArraySize; i != size; ++i)
426         keyArray[i] = i + 1;
427     keyArraySize = size;
428 }
429 
createKey()430 QPixmapCache::Key QPMCache::createKey()
431 {
432     if (freeKey == keyArraySize)
433         resizeKeyArray(keyArraySize ? keyArraySize << 1 : 2);
434     int id = freeKey;
435     freeKey = keyArray[id];
436     QPixmapCache::Key key;
437     QPixmapCache::KeyData *d = QPMCache::getKeyData(&key);
438     d->key = ++id;
439     return key;
440 }
441 
releaseKey(const QPixmapCache::Key & key)442 void QPMCache::releaseKey(const QPixmapCache::Key &key)
443 {
444     if (key.d->key > keyArraySize || key.d->key <= 0)
445         return;
446     key.d->key--;
447     keyArray[key.d->key] = freeKey;
448     freeKey = key.d->key;
449     key.d->isValid = false;
450     key.d->key = 0;
451 }
452 
clear()453 void QPMCache::clear()
454 {
455     free(keyArray);
456     keyArray = nullptr;
457     freeKey = 0;
458     keyArraySize = 0;
459     //Mark all keys as invalid
460     QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QPixmapCacheEntry>::keys();
461     for (int i = 0; i < keys.size(); ++i)
462         keys.at(i).d->isValid = false;
463     QCache<QPixmapCache::Key, QPixmapCacheEntry>::clear();
464 }
465 
getKeyData(QPixmapCache::Key * key)466 QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key)
467 {
468     if (!key->d)
469         key->d = new QPixmapCache::KeyData;
470     return key->d;
471 }
472 
Q_GLOBAL_STATIC(QPMCache,pm_cache)473 Q_GLOBAL_STATIC(QPMCache, pm_cache)
474 
475 int Q_AUTOTEST_EXPORT q_QPixmapCache_keyHashSize()
476 {
477     return pm_cache()->size();
478 }
479 
~QPixmapCacheEntry()480 QPixmapCacheEntry::~QPixmapCacheEntry()
481 {
482     pm_cache()->releaseKey(key);
483 }
484 
485 #if QT_DEPRECATED_SINCE(5, 13)
486 /*!
487     \obsolete
488     \overload
489 
490     Use bool find(const QString &, QPixmap *) instead.
491 
492     Returns the pixmap associated with the \a key in the cache, or
493     null if there is no such pixmap.
494 
495     \warning If valid, you should copy the pixmap immediately (this is
496     fast). Subsequent insertions into the cache could cause the
497     pointer to become invalid. For this reason, we recommend you use
498     bool find(const QString&, QPixmap*) instead.
499 
500     Example:
501     \snippet code/src_gui_image_qpixmapcache.cpp 0
502 */
503 
find(const QString & key)504 QPixmap *QPixmapCache::find(const QString &key)
505 {
506     if (!qt_pixmapcache_thread_test())
507         return nullptr;
508     return pm_cache()->object(key);
509 }
510 
511 
512 /*!
513     \obsolete
514 
515     Use bool find(const QString &, QPixmap *) instead.
516 */
517 
find(const QString & key,QPixmap & pixmap)518 bool QPixmapCache::find(const QString &key, QPixmap &pixmap)
519 {
520     return find(key, &pixmap);
521 }
522 #endif
523 
524 /*!
525     Looks for a cached pixmap associated with the given \a key in the cache.
526     If the pixmap is found, the function sets \a pixmap to that pixmap and
527     returns \c true; otherwise it leaves \a pixmap alone and returns \c false.
528 
529     \since 4.6
530 
531     Example:
532     \snippet code/src_gui_image_qpixmapcache.cpp 1
533 */
534 
find(const QString & key,QPixmap * pixmap)535 bool QPixmapCache::find(const QString &key, QPixmap *pixmap)
536 {
537     if (!qt_pixmapcache_thread_test())
538         return false;
539     QPixmap *ptr = pm_cache()->object(key);
540     if (ptr && pixmap)
541         *pixmap = *ptr;
542     return ptr != nullptr;
543 }
544 
545 /*!
546     Looks for a cached pixmap associated with the given \a key in the cache.
547     If the pixmap is found, the function sets \a pixmap to that pixmap and
548     returns \c true; otherwise it leaves \a pixmap alone and returns \c false. If
549     the pixmap is not found, it means that the \a key is no longer valid,
550     so it will be released for the next insertion.
551 
552     \since 4.6
553 */
find(const Key & key,QPixmap * pixmap)554 bool QPixmapCache::find(const Key &key, QPixmap *pixmap)
555 {
556     if (!qt_pixmapcache_thread_test())
557         return false;
558     //The key is not valid anymore, a flush happened before probably
559     if (!key.d || !key.d->isValid)
560         return false;
561     QPixmap *ptr = pm_cache()->object(key);
562     if (ptr && pixmap)
563         *pixmap = *ptr;
564     return ptr != nullptr;
565 }
566 
567 /*!
568     Inserts a copy of the pixmap \a pixmap associated with the \a key into
569     the cache.
570 
571     All pixmaps inserted by the Qt library have a key starting with
572     "$qt", so your own pixmap keys should never begin "$qt".
573 
574     When a pixmap is inserted and the cache is about to exceed its
575     limit, it removes pixmaps until there is enough room for the
576     pixmap to be inserted.
577 
578     The oldest pixmaps (least recently accessed in the cache) are
579     deleted when more space is needed.
580 
581     The function returns \c true if the object was inserted into the
582     cache; otherwise it returns \c false.
583 
584     \sa setCacheLimit()
585 */
586 
insert(const QString & key,const QPixmap & pixmap)587 bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap)
588 {
589     if (!qt_pixmapcache_thread_test())
590         return false;
591     return pm_cache()->insert(key, pixmap, cost(pixmap));
592 }
593 
594 /*!
595     Inserts a copy of the given \a pixmap into the cache and returns a key
596     that can be used to retrieve it.
597 
598     When a pixmap is inserted and the cache is about to exceed its
599     limit, it removes pixmaps until there is enough room for the
600     pixmap to be inserted.
601 
602     The oldest pixmaps (least recently accessed in the cache) are
603     deleted when more space is needed.
604 
605     \sa setCacheLimit(), replace()
606 
607     \since 4.6
608 */
insert(const QPixmap & pixmap)609 QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap)
610 {
611     if (!qt_pixmapcache_thread_test())
612         return QPixmapCache::Key();
613     return pm_cache()->insert(pixmap, cost(pixmap));
614 }
615 
616 /*!
617     Replaces the pixmap associated with the given \a key with the \a pixmap
618     specified. Returns \c true if the \a pixmap has been correctly inserted into
619     the cache; otherwise returns \c false.
620 
621     \sa setCacheLimit(), insert()
622 
623     \since 4.6
624 */
replace(const Key & key,const QPixmap & pixmap)625 bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap)
626 {
627     if (!qt_pixmapcache_thread_test())
628         return false;
629     //The key is not valid anymore, a flush happened before probably
630     if (!key.d || !key.d->isValid)
631         return false;
632     return pm_cache()->replace(key, pixmap, cost(pixmap));
633 }
634 
635 /*!
636     Returns the cache limit (in kilobytes).
637 
638     The default cache limit is 10240 KB.
639 
640     \sa setCacheLimit()
641 */
642 
cacheLimit()643 int QPixmapCache::cacheLimit()
644 {
645     return pm_cache()->maxCost();
646 }
647 
648 /*!
649     Sets the cache limit to \a n kilobytes.
650 
651     The default setting is 10240 KB.
652 
653     \sa cacheLimit()
654 */
655 
setCacheLimit(int n)656 void QPixmapCache::setCacheLimit(int n)
657 {
658     if (!qt_pixmapcache_thread_test())
659         return;
660     pm_cache()->setMaxCost(n);
661 }
662 
663 /*!
664   Removes the pixmap associated with \a key from the cache.
665 */
remove(const QString & key)666 void QPixmapCache::remove(const QString &key)
667 {
668     if (!qt_pixmapcache_thread_test())
669         return;
670     pm_cache()->remove(key);
671 }
672 
673 /*!
674   Removes the pixmap associated with \a key from the cache and releases
675   the key for a future insertion.
676 
677   \since 4.6
678 */
remove(const Key & key)679 void QPixmapCache::remove(const Key &key)
680 {
681     if (!qt_pixmapcache_thread_test())
682         return;
683     //The key is not valid anymore, a flush happened before probably
684     if (!key.d || !key.d->isValid)
685         return;
686     pm_cache()->remove(key);
687 }
688 
689 /*!
690     Removes all pixmaps from the cache.
691 */
692 
clear()693 void QPixmapCache::clear()
694 {
695     if (!QCoreApplication::closingDown() && !qt_pixmapcache_thread_test())
696         return;
697     QT_TRY {
698         if (pm_cache.exists())
699             pm_cache->clear();
700     } QT_CATCH(const std::bad_alloc &) {
701         // if we ran out of memory during pm_cache(), it's no leak,
702         // so just ignore it.
703     }
704 }
705 
flushDetachedPixmaps()706 void QPixmapCache::flushDetachedPixmaps()
707 {
708     pm_cache()->flushDetachedPixmaps(true);
709 }
710 
totalUsed()711 int QPixmapCache::totalUsed()
712 {
713     return (pm_cache()->totalCost()+1023) / 1024;
714 }
715 
716 /*!
717    \fn QPixmapCache::KeyData::KeyData()
718 
719    \internal
720 */
721 /*!
722    \fn QPixmapCache::KeyData::KeyData(const KeyData &other)
723    \internal
724 */
725 /*!
726    \fn QPixmapCache::KeyData::~KeyData()
727 
728    \internal
729 */
730 QT_END_NAMESPACE
731