don't discard iframe children.
[kdelibs.git] / khtml / misc / paintbuffer.cpp
blob15c0c1cf9c93d4ae709d96568581ac5e7e54bb9b
1 /*
2 * This file is part of the KDE libraries
4 * Copyright (C) 2007 Germain Garand <germain@ebooksfrance.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 #include "paintbuffer.h"
24 #include <QPixmap>
25 #include <QTimerEvent>
27 using namespace khtml;
29 const int PaintBuffer::maxPixelBuffering = 200*200;
30 const int PaintBuffer::leaseTime = 2*1000;
31 const int PaintBuffer::cleanupTime = 10*1000;
32 const int PaintBuffer::maxBuffers = 10;
34 namespace khtml {
36 class BufferSweeper: public QObject
38 public:
39 BufferSweeper(): QObject() { m_timer = 0; m_reset = false; }
41 void timerEvent(QTimerEvent* e) {
42 assert( m_timer == e->timerId() );
43 if (m_reset) {
44 m_reset = false;
45 return;
47 if (PaintBuffer::s_avail) {
48 while (PaintBuffer::s_avail->count()>1)
49 delete PaintBuffer::s_avail->pop();
50 if (PaintBuffer::s_avail->count())
51 PaintBuffer::s_avail->top()->reset();
53 if (!PaintBuffer::s_grabbed)
54 stop();
56 void start() {
57 if (m_timer) return;
58 m_timer = startTimer( PaintBuffer::cleanupTime );
60 void stop() {
61 if (m_timer)
62 killTimer( m_timer );
63 m_timer = 0;
65 void restart() {
66 stop();
67 start();
69 void reset() {
70 m_reset = true;
72 bool stopped() const { return !m_timer; }
73 int m_timer;
74 bool m_reset;
79 PaintBuffer::PaintBuffer()
80 : m_overflow(false),
81 m_grabbed(false),
82 m_renewTimer(false),
83 m_timer(0),
84 m_resetWidth(0),
85 m_resetHeight(0)
90 // static
91 void PaintBuffer::cleanup()
93 if (s_avail) {
94 qDeleteAll( *s_avail );
95 delete s_avail;
96 s_avail = 0;
98 if (s_grabbed) {
99 qDeleteAll( *s_grabbed );
100 delete s_grabbed;
101 s_grabbed = 0;
103 if (s_full) {
104 qDeleteAll( *s_full );
105 delete s_full;
106 s_full = 0;
108 if (s_sweeper) {
109 s_sweeper->deleteLater();
110 s_sweeper = 0;
114 // static
115 QPixmap *PaintBuffer::grab( QSize s )
117 if (!s_avail) {
118 s_avail = new QStack<PaintBuffer*>;
119 s_grabbed = new QStack<PaintBuffer*>;
120 s_sweeper = new BufferSweeper;
123 if (s_sweeper->stopped())
124 s_sweeper->start();
125 else
126 s_sweeper->reset();
128 if ( s_grabbed->count()+s_avail->count() >= maxBuffers ) {
129 if (!s_full)
130 s_full = new QStack<QPixmap*>;
131 s_full->push( new QPixmap(s.width(), s.height()) );
132 return s_full->top();
135 s_grabbed->push( s_avail->count() ? s_avail->pop() : new PaintBuffer );
136 QPixmap *ret = s_grabbed->top()->getBuf( s );
137 //kDebug() << "requested size:" << s << "real size:" << ret->size();
138 return ret;
141 // static
142 void PaintBuffer::release( QPixmap *px )
144 if (s_full && s_full->count()) {
145 assert( px == s_full->top() );
146 delete s_full->top();
147 s_full->pop();
148 return;
150 assert(px == &s_grabbed->top()->m_buf);
151 s_grabbed->top()->m_grabbed = false;
152 s_avail->push( s_grabbed->pop() );
155 void PaintBuffer::timerEvent(QTimerEvent* e)
157 assert( m_timer == e->timerId() );
158 if (m_grabbed)
159 return;
160 if (m_renewTimer) {
161 m_renewTimer = false;
162 return;
164 m_buf = QPixmap(m_resetWidth, m_resetHeight);
165 m_resetWidth = m_resetHeight = 0;
166 m_overflow = false;
167 killTimer( m_timer );
168 m_timer = 0;
171 void PaintBuffer::reset()
173 if (m_grabbed|m_renewTimer)
174 return;
175 m_resetWidth = m_resetHeight = 0;
176 m_buf = QPixmap();
177 m_overflow = false;
178 if( m_timer )
179 killTimer( m_timer );
180 m_timer = 0;
183 QPixmap *PaintBuffer::getBuf( QSize s )
185 assert( !m_grabbed );
186 if (s.isEmpty())
187 return 0;
189 m_grabbed = true;
190 bool cur_overflow = false;
191 int nw = qMax(m_buf.width(), s.width());
192 int nh = qMax(m_buf.height(), s.height());
194 if (!m_overflow && (nw*nh > maxPixelBuffering))
195 cur_overflow = true;
197 if (nw != m_buf.width() || nh != m_buf.height())
198 m_buf = QPixmap(nw, nh);
200 if (cur_overflow) {
201 m_overflow = true;
202 m_timer = startTimer( leaseTime );
203 } else if (m_overflow) {
204 int numPx = s.width()*s.height();
205 if( numPx > maxPixelBuffering ) {
206 m_renewTimer = true;
207 } else if (numPx > m_resetWidth*m_resetHeight) {
208 m_resetWidth = s.width();
209 m_resetHeight = s.height();
212 return &m_buf;
215 QStack<PaintBuffer*> *PaintBuffer::s_avail = 0;
216 QStack<PaintBuffer*> *PaintBuffer::s_grabbed = 0;
217 QStack<QPixmap*> * PaintBuffer::s_full = 0;
218 BufferSweeper* PaintBuffer::s_sweeper = 0;
220 // ### benchark me in release mode
221 #define USE_PIXMAP_CACHE
223 // static
224 BufferedPainter* BufferedPainter::start(QPainter*&p, const QRegion&rr)
226 if (rr.isEmpty())
227 return 0;
228 #ifdef USE_PIXMAP_CACHE
229 QPixmap *pm = PaintBuffer::grab(rr.boundingRect().size());
230 #else
231 QPixmap *pm = new QPixmap( rr.boundingRect().size() );
232 #endif
233 if (!pm || pm->isNull())
234 return 0;
235 return new BufferedPainter(pm, p, rr, true /*replacePainter*/);
238 // static
239 void BufferedPainter::end(QPainter*&p, BufferedPainter* bp, float opacity)
241 bp->transfer( opacity );
242 p = bp->originalPainter();
243 #ifdef USE_PIXMAP_CACHE
244 PaintBuffer::release( bp->buffer() );
245 #else
246 delete bp->buffer();
247 #endif
248 delete bp;