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