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