Changeset 561 for trunk/src/gui/image/qpixmapcache.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/image/qpixmapcache.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 41 41 42 42 #include "qpixmapcache.h" 43 #include "qcache.h"44 43 #include "qobject.h" 45 44 #include "qdebug.h" 46 47 #include "qpaintengine.h" 48 #include <private/qimage_p.h> 49 #include <private/qpixmap_raster_p.h> 45 #include "qpixmapcache_p.h" 50 46 51 47 QT_BEGIN_NAMESPACE … … 56 52 \brief The QPixmapCache class provides an application-wide cache for pixmaps. 57 53 58 \ingroup environment 59 \ingroup multimedia 54 \ingroup painting 60 55 61 56 This class is a tool for optimized drawing with QPixmap. You can … … 69 64 object for caching the pixmaps. 70 65 71 The cache associates a pixmap with a string (key). If two pixmaps 72 are inserted into the cache using equal keys, then the last pixmap 73 will hide the first pixmap. The QHash and QCache classes do 74 exactly the same. 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 \mdash 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. 75 76 76 77 The cache becomes full when the total size of all pixmaps in the 77 cache exceeds cacheLimit(). The initial cache limit is 1024 KB (1 78 MB); it is changed with setCacheLimit(). A pixmap takes roughly 79 (\e{width} * \e{height} * \e{depth})/8 bytes of memory. 78 cache exceeds cacheLimit(). The initial cache limit is 79 2048 KB (2 MB) on embedded platforms, 10240 KB (10 MB) on desktop 80 platforms; you can change this by calling setCacheLimit() with the 81 required value. 82 A pixmap takes roughly (\e{width} * \e{height} * \e{depth})/8 bytes of 83 memory. 80 84 81 85 The \e{Qt Quarterly} article 82 \l{http:// doc.trolltech.com/qq/qq12-qpixmapcache.html}{Optimizing86 \l{http://qt.nokia.com/doc/qq/qq12-qpixmapcache.html}{Optimizing 83 87 with QPixmapCache} explains how to use QPixmapCache to speed up 84 88 applications by caching the results of painting. … … 87 91 */ 88 92 89 #if defined(Q_WS_QWS) || defined(Q_OS_WINCE) 93 #if defined(Q_OS_SYMBIAN) 94 static int cache_limit = 1024; // 1048 KB cache limit for symbian 95 #elif defined(Q_WS_QWS) || defined(Q_WS_WINCE) 90 96 static int cache_limit = 2048; // 2048 KB cache limit for embedded 91 97 #else … … 93 99 #endif 94 100 95 // XXX: hw: is this a general concept we need to abstract? 96 class QDetachedPixmap : public QPixmap 97 { 98 public: 99 QDetachedPixmap(const QPixmap &pix) : QPixmap(pix) 100 { 101 if (data && data->classId() == QPixmapData::RasterClass) { 102 QRasterPixmapData *d = static_cast<QRasterPixmapData*>(data); 103 if (!d->image.isNull() && d->image.d->paintEngine 104 && !d->image.d->paintEngine->isActive()) 105 { 106 delete d->image.d->paintEngine; 107 d->image.d->paintEngine = 0; 108 } 109 } 110 } 111 }; 112 113 class QPMCache : public QObject, public QCache<qint64, QDetachedPixmap> 101 /*! 102 \class QPixmapCache::Key 103 \brief The QPixmapCache::Key class can be used for efficient access 104 to the QPixmapCache. 105 \since 4.6 106 107 Use QPixmapCache::insert() to receive an instance of Key generated 108 by the pixmap cache. You can store the key in your own objects for 109 a very efficient one-to-one object-to-pixmap mapping. 110 */ 111 112 /*! 113 Constructs an empty Key object. 114 */ 115 QPixmapCache::Key::Key() : d(0) 116 { 117 } 118 119 /*! 120 \internal 121 Constructs a copy of \a other. 122 */ 123 QPixmapCache::Key::Key(const Key &other) 124 { 125 if (other.d) 126 ++(other.d->ref); 127 d = other.d; 128 } 129 130 /*! 131 Destroys the key. 132 */ 133 QPixmapCache::Key::~Key() 134 { 135 if (d && --(d->ref) == 0) 136 delete d; 137 } 138 139 /*! 140 \internal 141 142 Returns true if this key is the same as the given \a key; otherwise returns 143 false. 144 */ 145 bool QPixmapCache::Key::operator ==(const Key &key) const 146 { 147 return (d == key.d); 148 } 149 150 /*! 151 \fn bool QPixmapCache::Key::operator !=(const Key &key) const 152 \internal 153 */ 154 155 /*! 156 \internal 157 */ 158 QPixmapCache::Key &QPixmapCache::Key::operator =(const Key &other) 159 { 160 if (d != other.d) { 161 if (other.d) 162 ++(other.d->ref); 163 if (d && --(d->ref) == 0) 164 delete d; 165 d = other.d; 166 } 167 return *this; 168 } 169 170 class QPMCache : public QObject, public QCache<QPixmapCache::Key, QPixmapCacheEntry> 114 171 { 115 172 Q_OBJECT 116 173 public: 117 QPMCache() 118 : QObject(0), 119 QCache<qint64, QDetachedPixmap>(cache_limit * 1024), 120 theid(0), ps(0), t(false) { } 121 ~QPMCache() { } 174 QPMCache(); 175 ~QPMCache(); 122 176 123 177 void timerEvent(QTimerEvent *); 124 178 bool insert(const QString& key, const QPixmap &pixmap, int cost); 179 QPixmapCache::Key insert(const QPixmap &pixmap, int cost); 180 bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost); 125 181 bool remove(const QString &key); 182 bool remove(const QPixmapCache::Key &key); 183 184 void resizeKeyArray(int size); 185 QPixmapCache::Key createKey(); 186 void releaseKey(const QPixmapCache::Key &key); 187 void clear(); 126 188 127 189 QPixmap *object(const QString &key) const; 190 QPixmap *object(const QPixmapCache::Key &key) const; 191 192 static inline QPixmapCache::KeyData *get(const QPixmapCache::Key &key) 193 {return key.d;} 194 195 static QPixmapCache::KeyData* getKeyData(QPixmapCache::Key *key); 128 196 129 197 private: 130 QHash<QString, qint64> cacheKeys;198 int *keyArray; 131 199 int theid; 132 200 int ps; 201 int keyArraySize; 202 int freeKey; 203 QHash<QString, QPixmapCache::Key> cacheKeys; 133 204 bool t; 134 205 }; 206 135 207 QT_BEGIN_INCLUDE_NAMESPACE 136 208 #include "qpixmapcache.moc" 137 209 QT_END_INCLUDE_NAMESPACE 138 210 211 uint qHash(const QPixmapCache::Key &k) 212 { 213 return qHash(QPMCache::get(k)->key); 214 } 215 216 QPMCache::QPMCache() 217 : QObject(0), 218 QCache<QPixmapCache::Key, QPixmapCacheEntry>(cache_limit * 1024), 219 keyArray(0), theid(0), ps(0), keyArraySize(0), freeKey(0), t(false) 220 { 221 } 222 QPMCache::~QPMCache() 223 { 224 clear(); 225 free(keyArray); 226 } 227 139 228 /* 140 This is supposed to cut the cache size down by about 80-90% in a229 This is supposed to cut the cache size down by about 25% in a 141 230 minute once the application becomes idle, to let any inserted pixmap 142 231 remain in the cache for some time before it becomes a candidate for … … 147 236 timer so Qt won't keep the CPU from going into sleep mode. 148 237 */ 149 150 238 void QPMCache::timerEvent(QTimerEvent *) 151 239 { … … 156 244 ps = totalCost(); 157 245 158 QHash<QString, qint64>::iterator it = cacheKeys.begin();246 QHash<QString, QPixmapCache::Key>::iterator it = cacheKeys.begin(); 159 247 while (it != cacheKeys.end()) { 160 248 if (!contains(it.value())) { 249 releaseKey(it.value()); 161 250 it = cacheKeys.erase(it); 162 251 } else { … … 177 266 QPixmap *QPMCache::object(const QString &key) const 178 267 { 179 return QCache<qint64, QDetachedPixmap>::object(cacheKeys.value(key, -1)); 180 } 181 268 QPixmapCache::Key cacheKey = cacheKeys.value(key); 269 if (!cacheKey.d || !cacheKey.d->isValid) { 270 const_cast<QPMCache *>(this)->cacheKeys.remove(key); 271 return 0; 272 } 273 QPixmap *ptr = QCache<QPixmapCache::Key, QPixmapCacheEntry>::object(cacheKey); 274 //We didn't find the pixmap in the cache, the key is not valid anymore 275 if (!ptr) { 276 const_cast<QPMCache *>(this)->cacheKeys.remove(key); 277 } 278 return ptr; 279 } 280 281 QPixmap *QPMCache::object(const QPixmapCache::Key &key) const 282 { 283 Q_ASSERT(key.d->isValid); 284 QPixmap *ptr = QCache<QPixmapCache::Key, QPixmapCacheEntry>::object(key); 285 //We didn't find the pixmap in the cache, the key is not valid anymore 286 if (!ptr) 287 const_cast<QPMCache *>(this)->releaseKey(key); 288 return ptr; 289 } 182 290 183 291 bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost) 184 292 { 185 qint64 cacheKey = pixmap.cacheKey(); 186 if (QCache<qint64, QDetachedPixmap>::object(cacheKey)) { 187 cacheKeys.insert(key, cacheKey); 188 return true; 189 } 190 bool success = QCache<qint64, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); 293 QPixmapCache::Key cacheKey; 294 QPixmapCache::Key oldCacheKey = cacheKeys.value(key); 295 //If for the same key we add already a pixmap we should delete it 296 if (oldCacheKey.d) { 297 QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(oldCacheKey); 298 cacheKeys.remove(key); 299 } 300 301 //we create a new key the old one has been removed 302 cacheKey = createKey(); 303 304 bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost); 191 305 if (success) { 192 306 cacheKeys.insert(key, cacheKey); … … 195 309 t = false; 196 310 } 311 } else { 312 //Insertion failed we released the new allocated key 313 releaseKey(cacheKey); 197 314 } 198 315 return success; 199 316 } 200 317 318 QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost) 319 { 320 QPixmapCache::Key cacheKey = createKey(); 321 bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost); 322 if (success) { 323 if (!theid) { 324 theid = startTimer(30000); 325 t = false; 326 } 327 } else { 328 //Insertion failed we released the key and return an invalid one 329 releaseKey(cacheKey); 330 } 331 return cacheKey; 332 } 333 334 bool QPMCache::replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost) 335 { 336 Q_ASSERT(key.d->isValid); 337 //If for the same key we had already an entry so we should delete the pixmap and use the new one 338 QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(key); 339 340 QPixmapCache::Key cacheKey = createKey(); 341 342 bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost); 343 if (success) { 344 if(!theid) { 345 theid = startTimer(30000); 346 t = false; 347 } 348 const_cast<QPixmapCache::Key&>(key) = cacheKey; 349 } else { 350 //Insertion failed we released the key 351 releaseKey(cacheKey); 352 } 353 return success; 354 } 355 201 356 bool QPMCache::remove(const QString &key) 202 357 { 203 qint64 cacheKey = cacheKeys.value(key, -1); 358 QPixmapCache::Key cacheKey = cacheKeys.value(key); 359 //The key was not in the cache 360 if (!cacheKey.d) 361 return false; 204 362 cacheKeys.remove(key); 205 return QCache<qint64, QDetachedPixmap>::remove(cacheKey); 363 return QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(cacheKey); 364 } 365 366 bool QPMCache::remove(const QPixmapCache::Key &key) 367 { 368 return QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(key); 369 } 370 371 void QPMCache::resizeKeyArray(int size) 372 { 373 if (size <= keyArraySize || size == 0) 374 return; 375 keyArray = q_check_ptr(reinterpret_cast<int *>(realloc(keyArray, 376 size * sizeof(int)))); 377 for (int i = keyArraySize; i != size; ++i) 378 keyArray[i] = i + 1; 379 keyArraySize = size; 380 } 381 382 QPixmapCache::Key QPMCache::createKey() 383 { 384 if (freeKey == keyArraySize) 385 resizeKeyArray(keyArraySize ? keyArraySize << 1 : 2); 386 int id = freeKey; 387 freeKey = keyArray[id]; 388 QPixmapCache::Key key; 389 QPixmapCache::KeyData *d = QPMCache::getKeyData(&key); 390 d->key = ++id; 391 return key; 392 } 393 394 void QPMCache::releaseKey(const QPixmapCache::Key &key) 395 { 396 if (key.d->key > keyArraySize || key.d->key <= 0) 397 return; 398 key.d->key--; 399 keyArray[key.d->key] = freeKey; 400 freeKey = key.d->key; 401 key.d->isValid = false; 402 key.d->key = 0; 403 } 404 405 void QPMCache::clear() 406 { 407 free(keyArray); 408 keyArray = 0; 409 freeKey = 0; 410 keyArraySize = 0; 411 //Mark all keys as invalid 412 QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QPixmapCacheEntry>::keys(); 413 for (int i = 0; i < keys.size(); ++i) 414 keys.at(i).d->isValid = false; 415 QCache<QPixmapCache::Key, QPixmapCacheEntry>::clear(); 416 } 417 418 QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key) 419 { 420 if (!key->d) 421 key->d = new QPixmapCache::KeyData; 422 return key->d; 206 423 } 207 424 208 425 Q_GLOBAL_STATIC(QPMCache, pm_cache) 209 426 210 /*! 211 \obsolete 427 int Q_AUTOTEST_EXPORT q_QPixmapCache_keyHashSize() 428 { 429 return pm_cache()->size(); 430 } 431 432 QPixmapCacheEntry::~QPixmapCacheEntry() 433 { 434 pm_cache()->releaseKey(key); 435 } 436 437 /*! 438 \obsolete 212 439 \overload 213 440 … … 218 445 fast). Subsequent insertions into the cache could cause the 219 446 pointer to become invalid. For this reason, we recommend you use 220 find(const QString&, QPixmap&) instead.447 bool find(const QString&, QPixmap*) instead. 221 448 222 449 Example: … … 231 458 232 459 /*! 233 Looks for a cached pixmap associated with the \a key in the cache. 234 If the pixmap is found, the function sets \a pm to that pixmap and 235 returns true; otherwise it leaves \a pm alone and returns false. 460 \obsolete 461 462 Use bool find(const QString&, QPixmap*) instead. 463 */ 464 465 bool QPixmapCache::find(const QString &key, QPixmap& pixmap) 466 { 467 return find(key, &pixmap); 468 } 469 470 /*! 471 Looks for a cached pixmap associated with the given \a key in the cache. 472 If the pixmap is found, the function sets \a pixmap to that pixmap and 473 returns true; otherwise it leaves \a pixmap alone and returns false. 474 475 \since 4.6 236 476 237 477 Example: … … 239 479 */ 240 480 241 bool QPixmapCache::find(const QString &key, QPixmap & pm)481 bool QPixmapCache::find(const QString &key, QPixmap* pixmap) 242 482 { 243 483 QPixmap *ptr = pm_cache()->object(key); 244 if (ptr )245 pm= *ptr;484 if (ptr && pixmap) 485 *pixmap = *ptr; 246 486 return ptr != 0; 247 487 } 248 488 249 250 /*! 251 Inserts a copy of the pixmap \a pm associated with the \a key into 489 /*! 490 Looks for a cached pixmap associated with the given \a key in the cache. 491 If the pixmap is found, the function sets \a pixmap to that pixmap and 492 returns true; otherwise it leaves \a pixmap alone and returns false. If 493 the pixmap is not found, it means that the \a key is no longer valid, 494 so it will be released for the next insertion. 495 496 \since 4.6 497 */ 498 bool QPixmapCache::find(const Key &key, QPixmap* pixmap) 499 { 500 //The key is not valid anymore, a flush happened before probably 501 if (!key.d || !key.d->isValid) 502 return false; 503 QPixmap *ptr = pm_cache()->object(key); 504 if (ptr && pixmap) 505 *pixmap = *ptr; 506 return ptr != 0; 507 } 508 509 /*! 510 Inserts a copy of the pixmap \a pixmap associated with the \a key into 252 511 the cache. 253 512 … … 268 527 */ 269 528 270 bool QPixmapCache::insert(const QString &key, const QPixmap &pm) 271 { 272 return pm_cache()->insert(key, pm, pm.width() * pm.height() * pm.depth() / 8); 529 bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap) 530 { 531 return pm_cache()->insert(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); 532 } 533 534 /*! 535 Inserts a copy of the given \a pixmap into the cache and returns a key 536 that can be used to retrieve it. 537 538 When a pixmap is inserted and the cache is about to exceed its 539 limit, it removes pixmaps until there is enough room for the 540 pixmap to be inserted. 541 542 The oldest pixmaps (least recently accessed in the cache) are 543 deleted when more space is needed. 544 545 \sa setCacheLimit(), replace() 546 547 \since 4.6 548 */ 549 QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap) 550 { 551 return pm_cache()->insert(pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); 552 } 553 554 /*! 555 Replaces the pixmap associated with the given \a key with the \a pixmap 556 specified. Returns true if the \a pixmap has been correctly inserted into 557 the cache; otherwise returns false. 558 559 \sa setCacheLimit(), insert() 560 561 \since 4.6 562 */ 563 bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap) 564 { 565 //The key is not valid anymore, a flush happened before probably 566 if (!key.d || !key.d->isValid) 567 return false; 568 return pm_cache()->replace(key, pixmap, pixmap.width() * pixmap.height() * pixmap.depth() / 8); 273 569 } 274 570 … … 276 572 Returns the cache limit (in kilobytes). 277 573 278 The default cache limit is 2048 KB for Embedded, 10240 KB for Desktops. 574 The default cache limit is 2048 KB on embedded platforms, 10240 KB on 575 desktop platforms. 279 576 280 577 \sa setCacheLimit() … … 289 586 Sets the cache limit to \a n kilobytes. 290 587 291 The default setting is 1024 kilobytes. 588 The default setting is 2048 KB on embedded platforms, 10240 KB on 589 desktop platforms. 292 590 293 591 \sa cacheLimit() … … 308 606 } 309 607 608 /*! 609 Removes the pixmap associated with \a key from the cache and releases 610 the key for a future insertion. 611 612 \since 4.6 613 */ 614 void QPixmapCache::remove(const Key &key) 615 { 616 //The key is not valid anymore, a flush happened before probably 617 if (!key.d || !key.d->isValid) 618 return; 619 pm_cache()->remove(key); 620 } 310 621 311 622 /*! … … 315 626 void QPixmapCache::clear() 316 627 { 317 pm_cache()->clear(); 628 QT_TRY { 629 pm_cache()->clear(); 630 } QT_CATCH(const std::bad_alloc &) { 631 // if we ran out of memory during pm_cache(), it's no leak, 632 // so just ignore it. 633 } 318 634 } 319 635
Note:
See TracChangeset
for help on using the changeset viewer.