Qt 4.8
qpixmapcache.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #define Q_TEST_QPIXMAPCACHE
43 #include "qpixmapcache.h"
44 #include "qobject.h"
45 #include "qdebug.h"
46 #include "qpixmapcache_p.h"
47 
49 
96 #if defined(Q_WS_QWS) || defined(Q_WS_WINCE)
97 static int cache_limit = 2048; // 2048 KB cache limit for embedded
98 #else
99 static int cache_limit = 10240; // 10 MB cache limit for desktop
100 #endif
101 
120 {
121 }
122 
131 {
132  if (other.d)
133  ++(other.d->ref);
134  d = other.d;
135 }
136 
141 {
142  if (d && --(d->ref) == 0)
143  delete d;
144 }
145 
156 {
157  return (d == key.d);
158 }
159 
169 {
170  if (d != other.d) {
171  if (other.d)
172  ++(other.d->ref);
173  if (d && --(d->ref) == 0)
174  delete d;
175  d = other.d;
176  }
177  return *this;
178 }
179 
180 class QPMCache : public QObject, public QCache<QPixmapCache::Key, QPixmapCacheEntry>
181 {
182  Q_OBJECT
183 public:
184  QPMCache();
185  ~QPMCache();
186 
187  void timerEvent(QTimerEvent *);
188  bool insert(const QString& key, const QPixmap &pixmap, int cost);
189  QPixmapCache::Key insert(const QPixmap &pixmap, int cost);
190  bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost);
191  bool remove(const QString &key);
192  bool remove(const QPixmapCache::Key &key);
193 
194  void resizeKeyArray(int size);
195  QPixmapCache::Key createKey();
196  void releaseKey(const QPixmapCache::Key &key);
197  void clear();
198 
199  QPixmap *object(const QString &key) const;
200  QPixmap *object(const QPixmapCache::Key &key) const;
201 
202  static inline QPixmapCache::KeyData *get(const QPixmapCache::Key &key)
203  {return key.d;}
204 
205  static QPixmapCache::KeyData* getKeyData(QPixmapCache::Key *key);
206 
207  QList< QPair<QString,QPixmap> > allPixmaps() const;
208  bool flushDetachedPixmaps(bool nt);
209 
210 private:
211  enum { soon_time = 10000, flush_time = 30000 };
212  int *keyArray;
213  int theid;
214  int ps;
216  int freeKey;
218  bool t;
219 };
220 
222 #include "qpixmapcache.moc"
224 
226 {
227  return qHash(QPMCache::get(k)->key);
228 }
229 
231  : QObject(0),
233  keyArray(0), theid(0), ps(0), keyArraySize(0), freeKey(0), t(false)
234 {
235 }
237 {
238  clear();
239  free(keyArray);
240 }
241 
242 /*
243  This is supposed to cut the cache size down by about 25% in a
244  minute once the application becomes idle, to let any inserted pixmap
245  remain in the cache for some time before it becomes a candidate for
246  cleaning-up, and to not cut down the size of the cache while the
247  cache is in active use.
248 
249  When the last detached pixmap has been deleted from the cache, kill the
250  timer so Qt won't keep the CPU from going into sleep mode. Currently
251  the timer is not restarted when the pixmap becomes unused, but it does
252  restart once something else is added (i.e. the cache space is actually needed).
253 
254  Returns true if any were removed.
255 */
257 {
258  int mc = maxCost();
259  setMaxCost(nt ? totalCost() * 3 / 4 : totalCost() -1);
260  setMaxCost(mc);
261  ps = totalCost();
262 
263  bool any = false;
265  while (it != cacheKeys.end()) {
266  if (!contains(it.value())) {
267  releaseKey(it.value());
268  it = cacheKeys.erase(it);
269  any = true;
270  } else {
271  ++it;
272  }
273  }
274 
275  return any;
276 }
277 
279 {
280  bool nt = totalCost() == ps;
281  if (!flushDetachedPixmaps(nt)) {
282  killTimer(theid);
283  theid = 0;
284  } else if (nt != t) {
285  killTimer(theid);
287  t = nt;
288  }
289 }
290 
291 
293 {
294  QPixmapCache::Key cacheKey = cacheKeys.value(key);
295  if (!cacheKey.d || !cacheKey.d->isValid) {
296  const_cast<QPMCache *>(this)->cacheKeys.remove(key);
297  return 0;
298  }
300  //We didn't find the pixmap in the cache, the key is not valid anymore
301  if (!ptr) {
302  const_cast<QPMCache *>(this)->cacheKeys.remove(key);
303  }
304  return ptr;
305 }
306 
308 {
309  Q_ASSERT(key.d->isValid);
311  //We didn't find the pixmap in the cache, the key is not valid anymore
312  if (!ptr)
313  const_cast<QPMCache *>(this)->releaseKey(key);
314  return ptr;
315 }
316 
317 bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost)
318 {
319  QPixmapCache::Key cacheKey;
320  QPixmapCache::Key oldCacheKey = cacheKeys.value(key);
321  //If for the same key we add already a pixmap we should delete it
322  if (oldCacheKey.d) {
324  cacheKeys.remove(key);
325  }
326 
327  //we create a new key the old one has been removed
328  cacheKey = createKey();
329 
330  bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
331  if (success) {
332  cacheKeys.insert(key, cacheKey);
333  if (!theid) {
335  t = false;
336  }
337  } else {
338  //Insertion failed we released the new allocated key
339  releaseKey(cacheKey);
340  }
341  return success;
342 }
343 
345 {
346  QPixmapCache::Key cacheKey = createKey();
347  bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
348  if (success) {
349  if (!theid) {
351  t = false;
352  }
353  } else {
354  //Insertion failed we released the key and return an invalid one
355  releaseKey(cacheKey);
356  }
357  return cacheKey;
358 }
359 
360 bool QPMCache::replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost)
361 {
362  Q_ASSERT(key.d->isValid);
363  //If for the same key we had already an entry so we should delete the pixmap and use the new one
365 
366  QPixmapCache::Key cacheKey = createKey();
367 
368  bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
369  if (success) {
370  if(!theid) {
372  t = false;
373  }
374  const_cast<QPixmapCache::Key&>(key) = cacheKey;
375  } else {
376  //Insertion failed we released the key
377  releaseKey(cacheKey);
378  }
379  return success;
380 }
381 
383 {
384  QPixmapCache::Key cacheKey = cacheKeys.value(key);
385  //The key was not in the cache
386  if (!cacheKey.d)
387  return false;
388  cacheKeys.remove(key);
390 }
391 
393 {
395 }
396 
398 {
399  if (size <= keyArraySize || size == 0)
400  return;
401  keyArray = q_check_ptr(reinterpret_cast<int *>(realloc(keyArray,
402  size * sizeof(int))));
403  for (int i = keyArraySize; i != size; ++i)
404  keyArray[i] = i + 1;
405  keyArraySize = size;
406 }
407 
409 {
410  if (freeKey == keyArraySize)
412  int id = freeKey;
413  freeKey = keyArray[id];
416  d->key = ++id;
417  return key;
418 }
419 
421 {
422  if (key.d->key > keyArraySize || key.d->key <= 0)
423  return;
424  key.d->key--;
425  keyArray[key.d->key] = freeKey;
426  freeKey = key.d->key;
427  key.d->isValid = false;
428  key.d->key = 0;
429 }
430 
432 {
433  free(keyArray);
434  keyArray = 0;
435  freeKey = 0;
436  keyArraySize = 0;
437  //Mark all keys as invalid
439  for (int i = 0; i < keys.size(); ++i)
440  keys.at(i).d->isValid = false;
442 }
443 
445 {
446  if (!key->d)
447  key->d = new QPixmapCache::KeyData;
448  return key->d;
449 }
450 
452 {
455  while (it != cacheKeys.end()) {
457  if (ptr)
459  ++it;
460  }
461  return r;
462 }
463 
464 
465 Q_GLOBAL_STATIC(QPMCache, pm_cache)
466 
468 {
469  return pm_cache()->size();
470 }
471 
473 {
474  pm_cache()->releaseKey(key);
475 }
476 
494 {
495  return pm_cache()->object(key);
496 }
497 
498 
505 bool QPixmapCache::find(const QString &key, QPixmap& pixmap)
506 {
507  return find(key, &pixmap);
508 }
509 
521 bool QPixmapCache::find(const QString &key, QPixmap* pixmap)
522 {
523  QPixmap *ptr = pm_cache()->object(key);
524  if (ptr && pixmap)
525  *pixmap = *ptr;
526  return ptr != 0;
527 }
528 
538 bool QPixmapCache::find(const Key &key, QPixmap* pixmap)
539 {
540  //The key is not valid anymore, a flush happened before probably
541  if (!key.d || !key.d->isValid)
542  return false;
543  QPixmap *ptr = pm_cache()->object(key);
544  if (ptr && pixmap)
545  *pixmap = *ptr;
546  return ptr != 0;
547 }
548 
569 bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap)
570 {
571  return pm_cache()->insert(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8);
572 }
573 
590 {
591  return pm_cache()->insert(pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8);
592 }
593 
603 bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap)
604 {
605  //The key is not valid anymore, a flush happened before probably
606  if (!key.d || !key.d->isValid)
607  return false;
608  return pm_cache()->replace(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8);
609 }
610 
621 {
622  return cache_limit;
623 }
624 
635 {
636  cache_limit = n;
637  pm_cache()->setMaxCost(1024 * cache_limit);
638 }
639 
644 {
645  pm_cache()->remove(key);
646 }
647 
655 {
656  //The key is not valid anymore, a flush happened before probably
657  if (!key.d || !key.d->isValid)
658  return;
659  pm_cache()->remove(key);
660 }
661 
667 {
668  QT_TRY {
669  pm_cache()->clear();
670  } QT_CATCH(const std::bad_alloc &) {
671  // if we ran out of memory during pm_cache(), it's no leak,
672  // so just ignore it.
673  }
674 }
675 
676 void QPixmapCache::flushDetachedPixmaps()
677 {
678  pm_cache()->flushDetachedPixmaps(true);
679 }
680 
681 int QPixmapCache::totalUsed()
682 {
683  return (pm_cache()->totalCost()+1023) / 1024;
684 }
685 
686 QList< QPair<QString,QPixmap> > QPixmapCache::allPixmaps()
687 {
688  return pm_cache()->allPixmaps();
689 }
690 
static QPixmapCache::KeyData * get(const QPixmapCache::Key &key)
static int cacheLimit()
Returns the cache limit (in kilobytes).
int startTimer(int interval)
Starts a timer and returns a timer identifier, or returns zero if it could not start a timer...
Definition: qobject.cpp:1623
double d
Definition: qnumeric_p.h:62
T * q_check_ptr(T *p)
Definition: qglobal.h:1857
uint qHash(const QPixmapCache::Key &k)
int * keyArray
T * object(const Key &key) const
Definition: qcache.h:147
int keyArraySize
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
int width() const
Returns the width of the pixmap.
Definition: qpixmap.cpp:630
int remove(const Key &key)
Removes all the items that have the key from the hash.
Definition: qhash.h:784
#define it(className, varName)
Definition: qcache.h:54
bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost)
void resizeKeyArray(int size)
#define QT_END_INCLUDE_NAMESPACE
This macro is equivalent to QT_BEGIN_NAMESPACE.
Definition: qglobal.h:92
void clear()
Definition: qcache.h:138
QPixmapCache::Key createKey()
int depth() const
Returns the depth of the pixmap.
Definition: qpixmap.cpp:695
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool operator==(const Key &key) const
Returns true if this key is the same as the given key; otherwise returns false.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
bool insert(const QString &key, const QPixmap &pixmap, int cost)
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
static QPixmap * find(const QString &key)
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
static QPixmapCache::KeyData * getKeyData(QPixmapCache::Key *key)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void timerEvent(QTimerEvent *)
This event handler can be reimplemented in a subclass to receive timer events for the object...
void releaseKey(const QPixmapCache::Key &key)
#define Q_GLOBAL_STATIC(TYPE, NAME)
Declares a global static variable with the given type and name.
Definition: qglobal.h:1968
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
static void clear()
Removes all pixmaps from the cache.
unsigned int uint
Definition: qglobal.h:996
const T * ptr(const T &t)
#define nt(var, enu)
bool flushDetachedPixmaps(bool nt)
#define QT_CATCH(A)
Definition: qglobal.h:1537
#define Q_OBJECT
Definition: qobjectdefs.h:157
Key & operator=(const Key &other)
QHash< QString, QPixmapCache::Key > cacheKeys
bool insert(const Key &key, T *object, int cost=1)
Definition: qcache.h:181
int Q_AUTOTEST_EXPORT q_QPixmapCache_keyHashSize()
bool contains(const QPixmapCache::Key &key) const
Definition: qcache.h:118
void clear()
The QPixmapCache::Key class can be used for efficient access to the QPixmapCache. ...
Definition: qpixmapcache.h:61
static int cache_limit
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:467
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
Key()
Constructs an empty Key object.
QList< QPair< QString, QPixmap > > allPixmaps() const
bool remove(const QString &key)
const Key key(const T &value) const
Returns the first key mapped to value.
Definition: qhash.h:674
static bool replace(const Key &key, const QPixmap &pixmap)
Replaces the pixmap associated with the given key with the pixmap specified.
static bool insert(const QString &key, const QPixmap &pixmap)
Inserts a copy of the pixmap pixmap associated with the key into the cache.
int key
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
static void setCacheLimit(int)
Sets the cache limit to n kilobytes.
#define Q_AUTOTEST_EXPORT
Definition: qglobal.h:1510
iterator begin()
Returns an STL-style iterator pointing to the first item in the hash.
Definition: qhash.h:464
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
QList< QPixmapCache::Key > keys() const
Definition: qcache.h:112
#define QT_BEGIN_INCLUDE_NAMESPACE
This macro is equivalent to QT_END_NAMESPACE.
Definition: qglobal.h:91
int height() const
Returns the height of the pixmap.
Definition: qpixmap.cpp:645
static void remove(const QString &key)
Removes the pixmap associated with key from the cache.
#define QT_TRY
Definition: qglobal.h:1536
iterator erase(iterator it)
Removes the (key, value) pair associated with the iterator pos from the hash, and returns an iterator...
Definition: qhash.h:827
The QPixmapCache class provides an application-wide cache for pixmaps.
Definition: qpixmapcache.h:57
bool remove(const Key &key)
Definition: qcache.h:155
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
QPixmap * object(const QString &key) const
void killTimer(int id)
Kills the timer with timer identifier, id.
Definition: qobject.cpp:1650
~Key()
Destroys the key.
friend class QPMCache
Definition: qpixmapcache.h:74