source: trunk/src/gui/image/qpixmapcache.cpp@ 503

Last change on this file since 503 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 9.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
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.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qpixmapcache.h"
43#include "qcache.h"
44#include "qobject.h"
45#include "qdebug.h"
46
47#include "qpaintengine.h"
48#include <private/qimage_p.h>
49#include <private/qpixmap_raster_p.h>
50
51QT_BEGIN_NAMESPACE
52
53/*!
54 \class QPixmapCache
55
56 \brief The QPixmapCache class provides an application-wide cache for pixmaps.
57
58 \ingroup environment
59 \ingroup multimedia
60
61 This class is a tool for optimized drawing with QPixmap. You can
62 use it to store temporary pixmaps that are expensive to generate
63 without using more storage space than cacheLimit(). Use insert()
64 to insert pixmaps, find() to find them, and clear() to empty the
65 cache.
66
67 QPixmapCache contains no member data, only static functions to
68 access the global pixmap cache. It creates an internal QCache
69 object for caching the pixmaps.
70
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.
75
76 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.
80
81 The \e{Qt Quarterly} article
82 \l{http://doc.trolltech.com/qq/qq12-qpixmapcache.html}{Optimizing
83 with QPixmapCache} explains how to use QPixmapCache to speed up
84 applications by caching the results of painting.
85
86 \sa QCache, QPixmap
87*/
88
89#if defined(Q_WS_QWS) || defined(Q_OS_WINCE)
90static int cache_limit = 2048; // 2048 KB cache limit for embedded
91#else
92static int cache_limit = 10240; // 10 MB cache limit for desktop
93#endif
94
95// XXX: hw: is this a general concept we need to abstract?
96class QDetachedPixmap : public QPixmap
97{
98public:
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
113class QPMCache : public QObject, public QCache<qint64, QDetachedPixmap>
114{
115 Q_OBJECT
116public:
117 QPMCache()
118 : QObject(0),
119 QCache<qint64, QDetachedPixmap>(cache_limit * 1024),
120 theid(0), ps(0), t(false) { }
121 ~QPMCache() { }
122
123 void timerEvent(QTimerEvent *);
124 bool insert(const QString& key, const QPixmap &pixmap, int cost);
125 bool remove(const QString &key);
126
127 QPixmap *object(const QString &key) const;
128
129private:
130 QHash<QString, qint64> cacheKeys;
131 int theid;
132 int ps;
133 bool t;
134};
135QT_BEGIN_INCLUDE_NAMESPACE
136#include "qpixmapcache.moc"
137QT_END_INCLUDE_NAMESPACE
138
139/*
140 This is supposed to cut the cache size down by about 80-90% in a
141 minute once the application becomes idle, to let any inserted pixmap
142 remain in the cache for some time before it becomes a candidate for
143 cleaning-up, and to not cut down the size of the cache while the
144 cache is in active use.
145
146 When the last pixmap has been deleted from the cache, kill the
147 timer so Qt won't keep the CPU from going into sleep mode.
148*/
149
150void QPMCache::timerEvent(QTimerEvent *)
151{
152 int mc = maxCost();
153 bool nt = totalCost() == ps;
154 setMaxCost(nt ? totalCost() * 3 / 4 : totalCost() -1);
155 setMaxCost(mc);
156 ps = totalCost();
157
158 QHash<QString, qint64>::iterator it = cacheKeys.begin();
159 while (it != cacheKeys.end()) {
160 if (!contains(it.value())) {
161 it = cacheKeys.erase(it);
162 } else {
163 ++it;
164 }
165 }
166
167 if (!size()) {
168 killTimer(theid);
169 theid = 0;
170 } else if (nt != t) {
171 killTimer(theid);
172 theid = startTimer(nt ? 10000 : 30000);
173 t = nt;
174 }
175}
176
177QPixmap *QPMCache::object(const QString &key) const
178{
179 return QCache<qint64, QDetachedPixmap>::object(cacheKeys.value(key, -1));
180}
181
182
183bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost)
184{
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);
191 if (success) {
192 cacheKeys.insert(key, cacheKey);
193 if (!theid) {
194 theid = startTimer(30000);
195 t = false;
196 }
197 }
198 return success;
199}
200
201bool QPMCache::remove(const QString &key)
202{
203 qint64 cacheKey = cacheKeys.value(key, -1);
204 cacheKeys.remove(key);
205 return QCache<qint64, QDetachedPixmap>::remove(cacheKey);
206}
207
208Q_GLOBAL_STATIC(QPMCache, pm_cache)
209
210/*!
211 \obsolete
212 \overload
213
214 Returns the pixmap associated with the \a key in the cache, or
215 null if there is no such pixmap.
216
217 \warning If valid, you should copy the pixmap immediately (this is
218 fast). Subsequent insertions into the cache could cause the
219 pointer to become invalid. For this reason, we recommend you use
220 find(const QString&, QPixmap&) instead.
221
222 Example:
223 \snippet doc/src/snippets/code/src_gui_image_qpixmapcache.cpp 0
224*/
225
226QPixmap *QPixmapCache::find(const QString &key)
227{
228 return pm_cache()->object(key);
229}
230
231
232/*!
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.
236
237 Example:
238 \snippet doc/src/snippets/code/src_gui_image_qpixmapcache.cpp 1
239*/
240
241bool QPixmapCache::find(const QString &key, QPixmap& pm)
242{
243 QPixmap *ptr = pm_cache()->object(key);
244 if (ptr)
245 pm = *ptr;
246 return ptr != 0;
247}
248
249
250/*!
251 Inserts a copy of the pixmap \a pm associated with the \a key into
252 the cache.
253
254 All pixmaps inserted by the Qt library have a key starting with
255 "$qt", so your own pixmap keys should never begin "$qt".
256
257 When a pixmap is inserted and the cache is about to exceed its
258 limit, it removes pixmaps until there is enough room for the
259 pixmap to be inserted.
260
261 The oldest pixmaps (least recently accessed in the cache) are
262 deleted when more space is needed.
263
264 The function returns true if the object was inserted into the
265 cache; otherwise it returns false.
266
267 \sa setCacheLimit()
268*/
269
270bool QPixmapCache::insert(const QString &key, const QPixmap &pm)
271{
272 return pm_cache()->insert(key, pm, pm.width() * pm.height() * pm.depth() / 8);
273}
274
275/*!
276 Returns the cache limit (in kilobytes).
277
278 The default cache limit is 2048 KB for Embedded, 10240 KB for Desktops.
279
280 \sa setCacheLimit()
281*/
282
283int QPixmapCache::cacheLimit()
284{
285 return cache_limit;
286}
287
288/*!
289 Sets the cache limit to \a n kilobytes.
290
291 The default setting is 1024 kilobytes.
292
293 \sa cacheLimit()
294*/
295
296void QPixmapCache::setCacheLimit(int n)
297{
298 cache_limit = n;
299 pm_cache()->setMaxCost(1024 * cache_limit);
300}
301
302/*!
303 Removes the pixmap associated with \a key from the cache.
304*/
305void QPixmapCache::remove(const QString &key)
306{
307 pm_cache()->remove(key);
308}
309
310
311/*!
312 Removes all pixmaps from the cache.
313*/
314
315void QPixmapCache::clear()
316{
317 pm_cache()->clear();
318}
319
320QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.