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"
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;
36 class BufferSweeper
: public QObject
39 BufferSweeper(): QObject() { m_timer
= 0; m_reset
= false; }
41 void timerEvent(QTimerEvent
* e
) {
42 assert( m_timer
== e
->timerId() );
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
)
58 m_timer
= startTimer( PaintBuffer::cleanupTime
);
72 bool stopped() const { return !m_timer
; }
79 PaintBuffer::PaintBuffer()
91 void PaintBuffer::cleanup()
94 qDeleteAll( *s_avail
);
99 qDeleteAll( *s_grabbed
);
104 qDeleteAll( *s_full
);
109 s_sweeper
->deleteLater();
115 QPixmap
*PaintBuffer::grab( QSize s
)
118 s_avail
= new QStack
<PaintBuffer
*>;
119 s_grabbed
= new QStack
<PaintBuffer
*>;
120 s_sweeper
= new BufferSweeper
;
123 if (s_sweeper
->stopped())
128 if ( s_grabbed
->count()+s_avail
->count() >= maxBuffers
) {
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();
142 void PaintBuffer::release( QPixmap
*px
)
144 if (s_full
&& s_full
->count()) {
145 assert( px
== s_full
->top() );
146 delete s_full
->top();
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() );
161 m_renewTimer
= false;
164 m_buf
= QPixmap(m_resetWidth
, m_resetHeight
);
165 m_resetWidth
= m_resetHeight
= 0;
167 killTimer( m_timer
);
171 void PaintBuffer::reset()
173 if (m_grabbed
|m_renewTimer
)
175 m_resetWidth
= m_resetHeight
= 0;
179 killTimer( m_timer
);
183 QPixmap
*PaintBuffer::getBuf( QSize s
)
185 assert( !m_grabbed
);
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
))
197 if (nw
!= m_buf
.width() || nh
!= m_buf
.height())
198 m_buf
= QPixmap(nw
, nh
);
202 m_timer
= startTimer( leaseTime
);
203 } else if (m_overflow
) {
204 int numPx
= s
.width()*s
.height();
205 if( numPx
> maxPixelBuffering
) {
207 } else if (numPx
> m_resetWidth
*m_resetHeight
) {
208 m_resetWidth
= s
.width();
209 m_resetHeight
= s
.height();
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
224 BufferedPainter
* BufferedPainter::start(QPainter
*&p
, const QRegion
&rr
)
228 #ifdef USE_PIXMAP_CACHE
229 QPixmap
*pm
= PaintBuffer::grab(rr
.boundingRect().size());
231 QPixmap
*pm
= new QPixmap( rr
.boundingRect().size() );
233 if (!pm
|| pm
->isNull())
235 return new BufferedPainter(pm
, p
, rr
, true /*replacePainter*/);
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() );