Replace 'i < len-1 && func(i+1)' by 'i+1 < len && func(i+1)'
[profile/ivi/qtbase.git] / src / gui / painting / qpaintbuffer.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qmath.h>
42 #include <private/qpainterpath_p.h>
43 #include <private/qpaintbuffer_p.h>
44 //#include <private/qtextengine_p.h>
45 #include <private/qfontengine_p.h>
46 #include <private/qemulationpaintengine_p.h>
47 #include <private/qimage_p.h>
48 #include <qstatictext.h>
49 #include <private/qstatictext_p.h>
50 #include <private/qrawfont_p.h>
51
52 #include <QDebug>
53
54 // #define QPAINTBUFFER_DEBUG_DRAW
55
56 QT_BEGIN_NAMESPACE
57
58 extern void qt_format_text(const QFont &font,
59                            const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
60                            int tabstops, int* tabarray, int tabarraylen,
61                            QPainter *painter);
62
63 QTextItemIntCopy::QTextItemIntCopy(const QTextItem &item)
64     : m_item(static_cast<const QTextItemInt &>(item))
65 {
66     QChar *chars = new QChar[m_item.num_chars];
67     unsigned short *logClusters = new unsigned short[m_item.num_chars];
68     memcpy(chars, m_item.chars, m_item.num_chars * sizeof(QChar));
69     memcpy(logClusters, m_item.logClusters, m_item.num_chars * sizeof(unsigned short));
70     m_item.chars = chars;
71     m_item.logClusters = logClusters;
72
73     const int size = QGlyphLayout::spaceNeededForGlyphLayout(m_item.glyphs.numGlyphs);
74     char *glyphLayoutData = new char[size];
75     QGlyphLayout glyphs(glyphLayoutData, m_item.glyphs.numGlyphs);
76     memcpy(glyphs.offsets, m_item.glyphs.offsets, m_item.glyphs.numGlyphs * sizeof(QFixedPoint));
77     memcpy(glyphs.glyphs, m_item.glyphs.glyphs, m_item.glyphs.numGlyphs * sizeof(HB_Glyph));
78     memcpy(glyphs.advances_x, m_item.glyphs.advances_x, m_item.glyphs.numGlyphs * sizeof(QFixed));
79     memcpy(glyphs.advances_y, m_item.glyphs.advances_y, m_item.glyphs.numGlyphs * sizeof(QFixed));
80     memcpy(glyphs.justifications, m_item.glyphs.justifications, m_item.glyphs.numGlyphs * sizeof(QGlyphJustification));
81     memcpy(glyphs.attributes, m_item.glyphs.attributes, m_item.glyphs.numGlyphs * sizeof(HB_GlyphAttributes));
82     m_item.glyphs = glyphs;
83
84     m_font = *m_item.f;
85     m_item.f = &m_font;
86
87     m_item.fontEngine->ref.ref(); // Increment reference count.
88 }
89
90 QTextItemIntCopy::~QTextItemIntCopy()
91 {
92     delete m_item.chars;
93     delete m_item.logClusters;
94     delete m_item.glyphs.data();
95     if (!m_item.fontEngine->ref.deref())
96         delete m_item.fontEngine;
97 }
98
99 /************************************************************************
100  *
101  * QPaintBufferSignalProxy
102  *
103  ************************************************************************/
104
105 Q_GLOBAL_STATIC(QPaintBufferSignalProxy, theSignalProxy)
106
107 QPaintBufferSignalProxy *QPaintBufferSignalProxy::instance()
108 {
109     return theSignalProxy();
110 }
111
112 /************************************************************************
113  *
114  * QPaintBufferPrivate
115  *
116  ************************************************************************/
117
118 QPaintBufferPrivate::QPaintBufferPrivate()
119     : ref(1), engine(0), penWidthAdjustment(0)
120     , calculateBoundingRect(true)
121     , cache(0)
122 {
123 }
124
125 QPaintBufferPrivate::~QPaintBufferPrivate()
126 {
127     QPaintBufferSignalProxy::instance()->emitAboutToDestroy(this);
128
129     for (int i = 0; i < commands.size(); ++i) {
130         const QPaintBufferCommand &cmd = commands.at(i);
131         if (cmd.id == QPaintBufferPrivate::Cmd_DrawTextItem)
132             delete reinterpret_cast<QTextItemIntCopy *>(qvariant_cast<void *>(variants.at(cmd.offset)));
133     }
134 }
135
136
137 inline void QPaintBufferPrivate::updateBoundingRect(const QRectF &br)
138 {
139     // transform to device coords and adjust for pen width
140     Q_ASSERT(engine && engine->painter());
141     QPainter *painter = engine->painter();
142     const QTransform transform = painter->transform();
143     QRectF devRect = transform.mapRect(br);
144     if (penWidthAdjustment > 0) {
145         devRect = devRect.adjusted(-penWidthAdjustment, -penWidthAdjustment,
146                                    penWidthAdjustment, penWidthAdjustment);
147     }
148
149     if (boundingRect.isEmpty()) {
150         boundingRect = devRect;
151     } else {
152         qreal min_x = qMin(devRect.left(), boundingRect.left());
153         qreal min_y = qMin(devRect.top(), boundingRect.top());
154         qreal max_x = qMax(devRect.right(), boundingRect.right());
155         qreal max_y = qMax(devRect.bottom(), boundingRect.bottom());
156         boundingRect = QRectF(min_x, min_y, max_x - min_x, max_y - min_y);
157     }
158     if (painter->hasClipping())
159         boundingRect &= transform.mapRect(painter->clipRegion().boundingRect());
160 }
161
162
163 /************************************************************************
164  *
165  * QPaintBuffer
166  *
167  ************************************************************************/
168
169
170
171 QPaintBuffer::QPaintBuffer()
172     : d_ptr(new QPaintBufferPrivate)
173 {
174 }
175
176 QPaintBuffer::~QPaintBuffer()
177 {
178     if (!d_ptr->ref.deref())
179         delete d_ptr;
180 }
181
182 QPaintBuffer::QPaintBuffer(const QPaintBuffer &other)
183     : QPaintDevice(), d_ptr(other.d_ptr)
184 {
185     d_ptr->ref.ref();
186 }
187
188 QPaintEngine *QPaintBuffer::paintEngine() const
189 {
190     QPaintBufferPrivate *d = const_cast<QPaintBuffer *>(this)->d_ptr;
191     if (!d->engine)
192         d->engine = new QPaintBufferEngine(d);
193     return d->engine;
194 }
195
196
197 int QPaintBuffer::metric(PaintDeviceMetric metric) const
198 {
199     int val = 0;
200     switch (metric) {
201     case PdmWidth:
202         val = qCeil(d_ptr->boundingRect.width());
203         break;
204     case PdmHeight:
205         val = qCeil(d_ptr->boundingRect.height());
206         break;
207     case PdmDpiX:
208     case PdmPhysicalDpiX:
209         val = qt_defaultDpiX();
210         break;
211     case PdmDpiY:
212     case PdmPhysicalDpiY:
213         val = qt_defaultDpiY();
214         break;
215     default:
216         val = QPaintDevice::metric(metric);
217     }
218
219     return val;
220 }
221
222 int QPaintBuffer::devType() const
223 {
224     return QInternal::PaintBuffer;
225 }
226
227 QPaintBuffer &QPaintBuffer::operator=(const QPaintBuffer &other)
228 {
229     if (other.d_ptr != d_ptr) {
230         QPaintBufferPrivate *data = other.d_ptr;
231         data->ref.ref();
232         if (d_ptr->ref.deref())
233             delete d_ptr;
234         d_ptr = data;
235     }
236     return *this;
237 }
238
239 bool QPaintBuffer::isEmpty() const
240 {
241     return d_ptr->commands.isEmpty();
242 }
243
244
245
246 void QPaintBuffer::draw(QPainter *painter, int frame) const
247 {
248 #ifdef QPAINTBUFFER_DEBUG_DRAW
249     qDebug() << "QPaintBuffer::draw() --------------------------------";
250
251     Q_D(const QPaintBuffer);
252     printf("Float buffer:");
253     for (int i=0; i<d->floats.size(); i++) {
254         if ((i % 10) == 0) {
255             printf("\n%4d-%4d: ", i, i+9);
256         }
257         printf("%4.2f  ", d->floats[i]);
258     }
259     printf("\n");
260
261     printf("Int Buffer:");
262     for (int i=0; i<d->ints.size(); i++) {
263         if ((i % 10) == 0) {
264             printf("\n%4d-%4d: ", i, i+10);
265         }
266         printf("%5d", d->ints[i]);
267     }
268     printf("\n");
269 #endif
270
271     processCommands(painter, frameStartIndex(frame), frameEndIndex(frame));
272
273 #ifdef QPAINTBUFFER_DEBUG_DRAW
274     qDebug() << "QPaintBuffer::draw() -------------------------------- DONE!";
275 #endif
276 }
277
278 int QPaintBuffer::frameStartIndex(int frame) const
279 {
280     return (frame == 0) ? 0 : d_ptr->frames.at(frame - 1);
281 }
282
283 int QPaintBuffer::frameEndIndex(int frame) const
284 {
285     return (frame == d_ptr->frames.size()) ? d_ptr->commands.size() : d_ptr->frames.at(frame);
286 }
287
288 int QPaintBuffer::processCommands(QPainter *painter, int begin, int end) const
289 {
290     if (!painter || !painter->isActive())
291         return 0;
292
293     QPaintEngineEx *xengine = painter->paintEngine()->isExtended()
294                               ? (QPaintEngineEx *) painter->paintEngine() : 0;
295     if (xengine) {
296         QPaintEngineExReplayer player;
297         player.processCommands(*this, painter, begin, end);
298     } else {
299         QPainterReplayer player;
300         player.processCommands(*this, painter, begin, end);
301     }
302
303     int depth = 0;
304     for (int i = begin; i < end; ++i) {
305         const QPaintBufferCommand &cmd = d_ptr->commands.at(i);
306         if (cmd.id == QPaintBufferPrivate::Cmd_Save)
307             ++depth;
308         else if (cmd.id == QPaintBufferPrivate::Cmd_Restore)
309             --depth;
310     }
311     return depth;
312 }
313
314 #ifndef QT_NO_DEBUG_STREAM
315 QString QPaintBuffer::commandDescription(int command) const
316 {
317     QString desc;
318     QDebug debug(&desc);
319
320     const QPaintBufferCommand &cmd = d_ptr->commands.at(command);
321
322     switch (cmd.id) {
323     case QPaintBufferPrivate::Cmd_Save: {
324         debug << "Cmd_Save";
325         break; }
326
327     case QPaintBufferPrivate::Cmd_Restore: {
328         debug << "Cmd_Restore";
329         break; }
330
331     case QPaintBufferPrivate::Cmd_SetBrush: {
332         QBrush brush = qvariant_cast<QBrush>(d_ptr->variants.at(cmd.offset));
333         debug << "Cmd_SetBrush: " << brush;
334         break; }
335
336     case QPaintBufferPrivate::Cmd_SetBrushOrigin: {
337         debug << "Cmd_SetBrushOrigin: " << d_ptr->variants.at(cmd.offset).toPointF();
338         break; }
339
340     case QPaintBufferPrivate::Cmd_SetCompositionMode: {
341         QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra;
342         debug << "ExCmd_SetCompositionMode, mode: " << mode;
343         break; }
344
345     case QPaintBufferPrivate::Cmd_SetOpacity: {
346         debug << "ExCmd_SetOpacity: " << d_ptr->variants.at(cmd.offset).toDouble();
347         break; }
348
349     case QPaintBufferPrivate::Cmd_DrawVectorPath: {
350         debug << "ExCmd_DrawVectorPath: size: " << cmd.size
351 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
352                  << "pts/elms:" << cmd.offset << cmd.offset2;
353         break; }
354
355     case QPaintBufferPrivate::Cmd_StrokeVectorPath: {
356         QPen pen = qvariant_cast<QPen>(d_ptr->variants.at(cmd.extra));
357         debug << "ExCmd_StrokeVectorPath: size: " << cmd.size
358 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
359                  << "pts/elms:" << cmd.offset << cmd.offset2 << pen;
360         break; }
361
362     case QPaintBufferPrivate::Cmd_FillVectorPath: {
363         QBrush brush = qvariant_cast<QBrush>(d_ptr->variants.at(cmd.extra));
364         debug << "ExCmd_FillVectorPath: size: " << cmd.size
365 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
366                  << "pts/elms:" << cmd.offset << cmd.offset2 << brush;
367         break; }
368
369     case QPaintBufferPrivate::Cmd_FillRectBrush: {
370         QBrush brush = qvariant_cast<QBrush>(d_ptr->variants.at(cmd.extra));
371         QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset);
372         debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush;
373         break; }
374
375     case QPaintBufferPrivate::Cmd_FillRectColor: {
376         QColor color = qvariant_cast<QColor>(d_ptr->variants.at(cmd.extra));
377         QRectF *rect = (QRectF *)(d_ptr->floats.constData() + cmd.offset);
378         debug << "ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color;
379         break; }
380
381     case QPaintBufferPrivate::Cmd_DrawPolygonF: {
382         debug << "ExCmd_DrawPolygonF, offset: " << cmd.offset << " size: " << cmd.size
383                  << " mode: " << cmd.extra
384                  << d_ptr->floats.at(cmd.offset)
385                  << d_ptr->floats.at(cmd.offset+1);
386         break; }
387
388     case QPaintBufferPrivate::Cmd_DrawPolygonI: {
389         debug << "ExCmd_DrawPolygonI, offset: " << cmd.offset << " size: " << cmd.size
390                  << " mode: " << cmd.extra
391                  << d_ptr->ints.at(cmd.offset)
392                  << d_ptr->ints.at(cmd.offset+1);
393         break; }
394
395     case QPaintBufferPrivate::Cmd_DrawEllipseF: {
396         debug << "ExCmd_DrawEllipseF, offset: " << cmd.offset;
397         break; }
398
399     case QPaintBufferPrivate::Cmd_DrawLineF: {
400         debug << "ExCmd_DrawLineF, offset: " << cmd.offset << " size: " << cmd.size;
401         break; }
402
403     case QPaintBufferPrivate::Cmd_DrawLineI: {
404         debug << "ExCmd_DrawLineI, offset: " << cmd.offset << " size: " << cmd.size;
405         break; }
406
407     case QPaintBufferPrivate::Cmd_DrawPointsF: {
408         debug << "ExCmd_DrawPointsF, offset: " << cmd.offset << " size: " << cmd.size;
409         break; }
410
411     case QPaintBufferPrivate::Cmd_DrawPointsI: {
412         debug << "ExCmd_DrawPointsI, offset: " << cmd.offset << " size: " << cmd.size;
413         break; }
414
415     case QPaintBufferPrivate::Cmd_DrawPolylineF: {
416         debug << "ExCmd_DrawPolylineF, offset: " << cmd.offset << " size: " << cmd.size;
417         break; }
418
419     case QPaintBufferPrivate::Cmd_DrawPolylineI: {
420         debug << "ExCmd_DrawPolylineI, offset: " << cmd.offset << " size: " << cmd.size;
421         break; }
422
423     case QPaintBufferPrivate::Cmd_DrawRectF: {
424         debug << "ExCmd_DrawRectF, offset: " << cmd.offset << " size: " << cmd.size;
425         break; }
426
427     case QPaintBufferPrivate::Cmd_DrawRectI: {
428         debug << "ExCmd_DrawRectI, offset: " << cmd.offset << " size: " << cmd.size;
429         break; }
430
431     case QPaintBufferPrivate::Cmd_SetClipEnabled: {
432         bool clipEnabled = d_ptr->variants.at(cmd.offset).toBool();
433         debug << "ExCmd_SetClipEnabled:" << clipEnabled;
434         break; }
435
436     case QPaintBufferPrivate::Cmd_ClipVectorPath: {
437         QVectorPathCmd path(d_ptr, cmd);
438         debug << "ExCmd_ClipVectorPath:" << path().elementCount();
439         break; }
440
441     case QPaintBufferPrivate::Cmd_ClipRect: {
442         QRect rect(QPoint(d_ptr->ints.at(cmd.offset), d_ptr->ints.at(cmd.offset + 1)),
443                    QPoint(d_ptr->ints.at(cmd.offset + 2), d_ptr->ints.at(cmd.offset + 3)));
444         debug << "ExCmd_ClipRect:" << rect << cmd.extra;
445         break; }
446
447     case QPaintBufferPrivate::Cmd_ClipRegion: {
448         QRegion region(d_ptr->variants.at(cmd.offset).value<QRegion>());
449         debug << "ExCmd_ClipRegion:" << region.boundingRect() << cmd.extra;
450         break; }
451
452     case QPaintBufferPrivate::Cmd_SetPen: {
453         QPen pen = qvariant_cast<QPen>(d_ptr->variants.at(cmd.offset));
454         debug << "Cmd_SetPen: " << pen;
455         break; }
456
457     case QPaintBufferPrivate::Cmd_SetTransform: {
458         QTransform xform = qvariant_cast<QTransform>(d_ptr->variants.at(cmd.offset));
459         debug << "Cmd_SetTransform, offset: " << cmd.offset << xform;
460         break; }
461
462     case QPaintBufferPrivate::Cmd_SetRenderHints: {
463         debug << "Cmd_SetRenderHints, hints: " << cmd.extra;
464         break; }
465
466     case QPaintBufferPrivate::Cmd_SetBackgroundMode: {
467         debug << "Cmd_SetBackgroundMode: " << cmd.extra;
468         break; }
469
470     case QPaintBufferPrivate::Cmd_DrawConvexPolygonF: {
471         debug << "Cmd_DrawConvexPolygonF, offset: " << cmd.offset << " size: " << cmd.size;
472         break; }
473
474     case QPaintBufferPrivate::Cmd_DrawConvexPolygonI: {
475         debug << "Cmd_DrawConvexPolygonI, offset: " << cmd.offset << " size: " << cmd.size;
476         break; }
477
478     case QPaintBufferPrivate::Cmd_DrawEllipseI: {
479         debug << "Cmd_DrawEllipseI, offset: " << cmd.offset;
480         break; }
481
482     case QPaintBufferPrivate::Cmd_DrawPixmapRect: {
483         QPixmap pm(d_ptr->variants.at(cmd.offset).value<QPixmap>());
484         QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1),
485                  d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3));
486
487         QRectF sr(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5),
488                   d_ptr->floats.at(cmd.extra+6), d_ptr->floats.at(cmd.extra+7));
489         debug << "Cmd_DrawPixmapRect:" << r << sr << pm.size();
490         break; }
491
492     case QPaintBufferPrivate::Cmd_DrawPixmapPos: {
493         QPixmap pm(d_ptr->variants.at(cmd.offset).value<QPixmap>());
494         QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1));
495         debug << "Cmd_DrawPixmapPos:" << pos << pm.size();
496         break; }
497
498     case QPaintBufferPrivate::Cmd_DrawTiledPixmap: {
499         QPixmap pm(d_ptr->variants.at(cmd.offset).value<QPixmap>());
500         QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1),
501                  d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3));
502
503         QPointF offset(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5));
504         debug << "Cmd_DrawTiledPixmap:" << r << offset << pm.size();
505         break; }
506
507     case QPaintBufferPrivate::Cmd_DrawImageRect: {
508         QImage image(d_ptr->variants.at(cmd.offset).value<QImage>());
509         QRectF r(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1),
510                  d_ptr->floats.at(cmd.extra+2), d_ptr->floats.at(cmd.extra+3));
511         QRectF sr(d_ptr->floats.at(cmd.extra+4), d_ptr->floats.at(cmd.extra+5),
512                   d_ptr->floats.at(cmd.extra+6), d_ptr->floats.at(cmd.extra+7));
513         debug << "Cmd_DrawImageRect:" << r << sr << image.size();
514         break; }
515
516     case QPaintBufferPrivate::Cmd_DrawImagePos: {
517         QImage image(d_ptr->variants.at(cmd.offset).value<QImage>());
518         QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1));
519         debug << "Cmd_DrawImagePos:" << pos << image.size();
520         break; }
521
522     case QPaintBufferPrivate::Cmd_DrawText: {
523         QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1));
524         QList<QVariant> variants(d_ptr->variants.at(cmd.offset).value<QList<QVariant> >());
525
526         QFont font(variants.at(0).value<QFont>());
527         QString text(variants.at(1).value<QString>());
528
529         debug << "Cmd_DrawText:" << pos << text << font.family();
530         break; }
531
532     case QPaintBufferPrivate::Cmd_DrawTextItem: {
533         QPointF pos(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1));
534         QTextItemIntCopy *tiCopy = reinterpret_cast<QTextItemIntCopy *>(qvariant_cast<void *>(d_ptr->variants.at(cmd.offset)));
535         QTextItemInt &ti = (*tiCopy)();
536         QString text(ti.text());
537
538         debug << "Cmd_DrawTextItem:" << pos << " " << text;
539         break; }
540     case QPaintBufferPrivate::Cmd_SystemStateChanged: {
541         QRegion systemClip(d_ptr->variants.at(cmd.offset).value<QRegion>());
542
543         debug << "Cmd_SystemStateChanged:" << systemClip;
544         break; }
545     case QPaintBufferPrivate::Cmd_Translate: {
546         QPointF delta(d_ptr->floats.at(cmd.extra), d_ptr->floats.at(cmd.extra+1));
547         debug << "Cmd_Translate:" << delta;
548         break; }
549     case QPaintBufferPrivate::Cmd_DrawStaticText: {
550         debug << "Cmd_DrawStaticText";
551         break; }
552     }
553
554     return desc;
555 }
556 #endif
557
558 QRectF QPaintBuffer::boundingRect() const
559 {
560     return d_ptr->boundingRect;
561 }
562
563 void QPaintBuffer::setBoundingRect(const QRectF &rect)
564 {
565     d_ptr->boundingRect = rect;
566     d_ptr->calculateBoundingRect = false;
567 }
568
569
570 class QPaintBufferEnginePrivate : public QPaintEngineExPrivate
571 {
572     Q_DECLARE_PUBLIC(QPaintBufferEngine)
573 public:
574     void systemStateChanged() {
575         Q_Q(QPaintBufferEngine);
576         q->buffer->addCommand(QPaintBufferPrivate::Cmd_SystemStateChanged, QVariant(systemClip));
577     }
578
579     QTransform last;
580 };
581
582
583 /************************************************************************
584  *
585  * QPaintBufferEngine
586  *
587  ************************************************************************/
588
589 QPaintBufferEngine::QPaintBufferEngine(QPaintBufferPrivate *b)
590     : QPaintEngineEx(*(new QPaintBufferEnginePrivate))
591     , buffer(b)
592     , m_begin_detected(false)
593     , m_save_detected(false)
594     , m_stream_raw_text_items(false)
595 {
596 }
597
598 bool QPaintBufferEngine::begin(QPaintDevice *)
599 {
600     Q_D(QPaintBufferEngine);
601     painter()->save();
602     d->systemStateChanged();
603     return true;
604 }
605
606 bool QPaintBufferEngine::end()
607 {
608     painter()->restore();
609     m_created_state = 0;
610     return true;
611 }
612
613 QPainterState *QPaintBufferEngine::createState(QPainterState *orig) const
614 {
615 #ifdef QPAINTBUFFER_DEBUG_DRAW
616     qDebug() << "QPaintBufferEngine: createState, orig=" << orig << ", current=" << state();
617 #endif
618
619     Q_ASSERT(!m_begin_detected);
620     Q_ASSERT(!m_save_detected);
621
622     if (orig == 0) {
623         m_begin_detected = true;
624         return new QPainterState();
625     } else {
626         m_save_detected = true;
627         return new QPainterState(orig);
628     }
629 }
630
631 void QPaintBufferEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
632 {
633 #ifdef QPAINTBUFFER_DEBUG_DRAW
634     qDebug() << "QPaintBufferEngine: clip vpath:" << path.elementCount() << "op:" << op;
635 #endif
636     QPaintBufferCommand *cmd =
637         buffer->addCommand(QPaintBufferPrivate::Cmd_ClipVectorPath, path);
638     cmd->extra = op;
639 }
640
641 void QPaintBufferEngine::clip(const QRect &rect, Qt::ClipOperation op)
642 {
643 #ifdef QPAINTBUFFER_DEBUG_DRAW
644     qDebug() << "QPaintBufferEngine: clip rect:" << rect << "op:" << op;
645 #endif
646     QPaintBufferCommand *cmd =
647         buffer->addCommand(QPaintBufferPrivate::Cmd_ClipRect, (int *) &rect, 4, 1);
648     cmd->extra = op;
649 }
650
651 void QPaintBufferEngine::clip(const QRegion &region, Qt::ClipOperation op)
652 {
653 #ifdef QPAINTBUFFER_DEBUG_DRAW
654     qDebug() << "QPaintBufferEngine: clip region br:" << region.boundingRect() << "op:" << op;
655 #endif
656     QPaintBufferCommand *cmd =
657         buffer->addCommand(QPaintBufferPrivate::Cmd_ClipRegion, QVariant(region));
658     cmd->extra = op;
659 }
660
661 void QPaintBufferEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
662 {
663     // ### TODO
664 //     QPaintBufferCommand *cmd =
665 //         buffer->addCommand(QPaintBufferPrivate::Cmd_ClipPath, QVariant(path));
666 //     cmd->extra = op;
667     QPaintEngineEx::clip(path, op);
668 }
669
670 void QPaintBufferEngine::clipEnabledChanged()
671 {
672 #ifdef QPAINTBUFFER_DEBUG_DRAW
673     qDebug() << "QPaintBufferEngine: clip enable change" << state()->clipEnabled;
674 #endif
675
676     buffer->addCommand(QPaintBufferPrivate::Cmd_SetClipEnabled, state()->clipEnabled);
677 }
678
679 void QPaintBufferEngine::penChanged()
680 {
681     const QPen &pen = state()->pen;
682
683     if (!buffer->commands.isEmpty()
684         && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetPen) {
685 #ifdef QPAINTBUFFER_DEBUG_DRAW
686     qDebug() << "QPaintBufferEngine: penChanged (compressed)" << state()->pen;
687 #endif
688         buffer->variants[buffer->commands.last().offset] = pen;
689         return;
690     }
691
692     if (buffer->calculateBoundingRect) {
693         if (pen.style() == Qt::NoPen) {
694             buffer->penWidthAdjustment = 0;
695         } else {
696             qreal penWidth = (pen.widthF() == 0) ? 1 : pen.widthF();
697             QPointF transformedWidth(penWidth, penWidth);
698             if (!pen.isCosmetic())
699                 transformedWidth = painter()->transform().map(transformedWidth);
700             buffer->penWidthAdjustment = transformedWidth.x() / 2.0;
701         }
702     }
703 #ifdef QPAINTBUFFER_DEBUG_DRAW
704     qDebug() << "QPaintBufferEngine: penChanged" << state()->pen;
705 #endif
706     buffer->addCommand(QPaintBufferPrivate::Cmd_SetPen, pen);
707 }
708
709 void QPaintBufferEngine::brushChanged()
710 {
711     const QBrush &brush = state()->brush;
712
713     if (!buffer->commands.isEmpty()
714         && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetBrush) {
715 #ifdef QPAINTBUFFER_DEBUG_DRAW
716         qDebug() << "QPaintBufferEngine: brushChanged (compressed)" << state()->brush;
717 #endif
718         buffer->variants[buffer->commands.last().offset] = brush;
719         return;
720     }
721
722 #ifdef QPAINTBUFFER_DEBUG_DRAW
723     qDebug() << "QPaintBufferEngine: brushChanged" << state()->brush;
724 #endif
725     buffer->addCommand(QPaintBufferPrivate::Cmd_SetBrush, brush);
726 }
727
728 void QPaintBufferEngine::brushOriginChanged()
729 {
730 #ifdef QPAINTBUFFER_DEBUG_DRAW
731     qDebug() << "QPaintBufferEngine: brush origin changed" << state()->brushOrigin;
732 #endif
733     buffer->addCommand(QPaintBufferPrivate::Cmd_SetBrushOrigin, state()->brushOrigin);
734 }
735
736 void QPaintBufferEngine::opacityChanged()
737 {
738 #ifdef QPAINTBUFFER_DEBUG_DRAW
739     qDebug() << "QPaintBufferEngine: opacity changed" << state()->opacity;
740 #endif
741     buffer->addCommand(QPaintBufferPrivate::Cmd_SetOpacity, state()->opacity);
742 }
743
744 void QPaintBufferEngine::compositionModeChanged()
745 {
746 #ifdef QPAINTBUFFER_DEBUG_DRAW
747     qDebug() << "QPaintBufferEngine: composition mode" << state()->composition_mode;
748 #endif
749     QPaintBufferCommand *cmd =
750         buffer->addCommand(QPaintBufferPrivate::Cmd_SetCompositionMode);
751     cmd->extra = state()->composition_mode;
752 }
753
754 void QPaintBufferEngine::renderHintsChanged()
755 {
756 #ifdef QPAINTBUFFER_DEBUG_DRAW
757     qDebug() << "QPaintBufferEngine: render hints changed" << state()->renderHints;
758 #endif
759     QPaintBufferCommand *cmd =
760         buffer->addCommand(QPaintBufferPrivate::Cmd_SetRenderHints);
761     cmd->extra = state()->renderHints;
762 }
763
764 void QPaintBufferEngine::transformChanged()
765 {
766     Q_D(QPaintBufferEngine);
767     const QTransform &transform = state()->matrix;
768
769     QTransform delta;
770
771     bool invertible = false;
772     if (transform.type() <= QTransform::TxScale && transform.type() == d->last.type())
773         delta = transform * d->last.inverted(&invertible);
774
775     d->last = transform;
776
777     if (invertible && delta.type() == QTransform::TxNone)
778         return;
779
780     if (invertible && delta.type() == QTransform::TxTranslate) {
781 #ifdef QPAINTBUFFER_DEBUG_DRAW
782         qDebug() << "QPaintBufferEngine: transformChanged (translate only) " << state()->matrix;
783 #endif
784         QPaintBufferCommand *cmd =
785             buffer->addCommand(QPaintBufferPrivate::Cmd_Translate);
786
787         qreal data[] = { delta.dx(), delta.dy() };
788         cmd->extra = buffer->addData((qreal *) data, 2);
789         return;
790     }
791
792     // ### accumulate, like in QBrush case...
793     if (!buffer->commands.isEmpty()
794         && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetTransform) {
795 #ifdef QPAINTBUFFER_DEBUG_DRAW
796         qDebug() << "QPaintBufferEngine: transformChanged (compressing) " << state()->matrix;
797 #endif
798         buffer->variants[buffer->commands.last().offset] = state()->matrix;
799         return;
800     }
801
802 #ifdef QPAINTBUFFER_DEBUG_DRAW
803         qDebug() << "QPaintBufferEngine: transformChanged:" << state()->matrix;
804 #endif
805     buffer->addCommand(QPaintBufferPrivate::Cmd_SetTransform, state()->matrix);
806 }
807
808 void QPaintBufferEngine::backgroundModeChanged()
809 {
810 #ifdef QPAINTBUFFER_DEBUG_DRAW
811     qDebug() << "QPaintEngineBuffer: background mode changed" << state()->bgMode;
812 #endif
813     QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_SetBackgroundMode);
814     cmd->extra = state()->bgMode;
815 }
816
817 void QPaintBufferEngine::draw(const QVectorPath &path)
818 {
819 #ifdef QPAINTBUFFER_DEBUG_DRAW
820     qDebug() << "QPaintBufferEngine: draw vpath:" << path.elementCount();
821 #endif
822
823     bool hasBrush = qbrush_style(state()->brush) != Qt::NoBrush;
824     bool hasPen = qpen_style(state()->pen) != Qt::NoPen
825                   && qbrush_style(qpen_brush(state()->pen)) != Qt::NoBrush;
826
827     if (hasPen || hasBrush)
828         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawVectorPath, path);
829 #ifdef QPAINTBUFFER_DEBUG_DRAW
830     else
831         qDebug() << " - no pen or brush active, discarded...\n";
832 #endif
833
834 //     if (buffer->calculateBoundingRect) {
835 //         QRealRect r = path.controlPointRect();
836 //         buffer->updateBoundingRect(QRectF(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1));
837 //     }
838 }
839
840 void QPaintBufferEngine::fill(const QVectorPath &path, const QBrush &brush)
841 {
842 #ifdef QPAINTBUFFER_DEBUG_DRAW
843     qDebug() << "QPaintBufferEngine: fill vpath:" << path.elementCount() << brush;
844 #endif
845     QPaintBufferCommand *cmd =
846         buffer->addCommand(QPaintBufferPrivate::Cmd_FillVectorPath, path);
847     cmd->extra = buffer->addData(QVariant(brush));
848 //     if (buffer->calculateBoundingRect) {
849 //         QRealRect r = path.controlPointRect();
850 //         buffer->updateBoundingRect(QRectF(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1));
851 //     }
852 }
853
854 void QPaintBufferEngine::stroke(const QVectorPath &path, const QPen &pen)
855 {
856 #ifdef QPAINTBUFFER_DEBUG_DRAW
857     qDebug() << "QPaintBufferEngine: stroke vpath:" << path.elementCount() << pen;
858 #endif
859     QPaintBufferCommand *cmd =
860         buffer->addCommand(QPaintBufferPrivate::Cmd_StrokeVectorPath, path);
861     cmd->extra = buffer->addData(QVariant(pen));
862 //     if (buffer->calculateBoundingRect) {
863 //         QRealRect r = path.controlPointRect();
864 //         buffer->updateBoundingRect(QRectF(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1));
865 //     }
866 }
867
868 void QPaintBufferEngine::fillRect(const QRectF &rect, const QBrush &brush)
869 {
870 #ifdef QPAINTBUFFER_DEBUG_DRAW
871     qDebug() << "QPaintBufferEngine: fillRect brush:" << rect << brush;
872 #endif
873     QPaintBufferCommand *cmd =
874         buffer->addCommand(QPaintBufferPrivate::Cmd_FillRectBrush, (qreal *) &rect, 4, 1);
875     cmd->extra = buffer->addData(brush);
876     if (buffer->calculateBoundingRect)
877         buffer->updateBoundingRect(rect);
878 }
879
880 void QPaintBufferEngine::fillRect(const QRectF &rect, const QColor &color)
881 {
882 #ifdef QPAINTBUFFER_DEBUG_DRAW
883     qDebug() << "QPaintBufferEngine: fillRect color:" << rect << color;
884 #endif
885     QPaintBufferCommand *cmd =
886         buffer->addCommand(QPaintBufferPrivate::Cmd_FillRectColor, (qreal *) &rect, 4, 1);
887     cmd->extra = buffer->addData(color);
888     if (buffer->calculateBoundingRect)
889         buffer->updateBoundingRect(rect);
890 }
891
892 void QPaintBufferEngine::drawRects(const QRect *rects, int rectCount)
893 {
894 #ifdef QPAINTBUFFER_DEBUG_DRAW
895     qDebug() << "QPaintBufferEngine: drawRectsI:" << rectCount;
896 #endif
897     QPaintBufferCommand *cmd =
898         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawRectI, (int *) rects, 4 * rectCount, rectCount);
899     cmd->extra = rectCount;
900
901     if (buffer->calculateBoundingRect) {
902         if (rectCount == 1) {
903             buffer->updateBoundingRect(rects[0]);
904         } else {
905             int min_x = rects[0].left();
906             int min_y = rects[0].top();
907             int max_x = rects[0].left() + rects[0].width();
908             int max_y = rects[0].top() + rects[0].height();
909             for (int i=1; i< rectCount; ++i) {
910                 if (rects[i].left() < min_x)
911                     min_x = rects[i].left();
912                 if (rects[i].top() < min_y)
913                     min_y = rects[i].top();
914                 if (rects[i].right() > max_x)
915                     max_x = rects[i].left() + rects[i].width();
916                 if (rects[i].bottom() > max_y)
917                     max_y = rects[i].top() + rects[i].height();
918
919             }
920             buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
921         }
922     }
923 }
924
925 void QPaintBufferEngine::drawRects(const QRectF *rects, int rectCount)
926 {
927 #ifdef QPAINTBUFFER_DEBUG_DRAW
928     qDebug() << "QPaintBufferEngine: drawRectsF:" << rectCount;
929 #endif
930     QPaintBufferCommand *cmd =
931         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawRectF, (qreal *) rects, 4 * rectCount, rectCount);
932     cmd->extra = rectCount;
933
934     if (buffer->calculateBoundingRect) {
935         if (rectCount == 1) {
936             buffer->updateBoundingRect(rects[0]);
937         } else {
938             qreal min_x = rects[0].left();
939             qreal min_y = rects[0].top();
940             qreal max_x = rects[0].right();
941             qreal max_y = rects[0].bottom();
942             for (int i=1; i< rectCount; ++i) {
943                 if (rects[i].left() < min_x)
944                     min_x = rects[i].left();
945                 if (rects[i].top() < min_y)
946                     min_y = rects[i].top();
947                 if (rects[i].right() > max_x)
948                     max_x = rects[i].right();
949                 if (rects[i].bottom() > max_y)
950                     max_y = rects[i].bottom();
951
952             }
953             buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
954         }
955     }
956 }
957
958 void QPaintBufferEngine::drawLines(const QLine *lines, int lineCount)
959 {
960 #ifdef QPAINTBUFFER_DEBUG_DRAW
961     qDebug() << "QPaintBufferEngine: drawLinesI:" << lineCount;
962 #endif
963     QPaintBufferCommand *cmd =
964         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawLineI, (int *) lines, 4 * lineCount, lineCount);
965     cmd->extra = lineCount;
966
967     if (buffer->calculateBoundingRect) {
968         int min_x = lines[0].p1().x();
969         int min_y = lines[0].p1().y();
970         int max_x = lines[0].p2().x();
971         int max_y = lines[0].p2().y();
972         if (min_x > max_x)
973             qSwap(min_x, max_x);
974         if (min_y > max_y)
975             qSwap(min_y, max_y);
976         for (int i=1; i < lineCount; ++i) {
977             int p1_x = lines[i].p1().x();
978             int p1_y = lines[i].p1().y();
979             int p2_x = lines[i].p2().x();
980             int p2_y = lines[i].p2().y();
981             if (p1_x > p2_x) {
982                 min_x = qMin(p2_x, min_x);
983                 max_x = qMax(p1_x, max_x);
984             } else {
985                 min_x = qMin(p1_x, min_x);
986                 max_x = qMax(p2_x, max_x);
987             }
988             if (p1_y > p2_y) {
989                 min_y = qMin(p2_y, min_y);
990                 max_y = qMax(p1_y, max_y);
991             } else {
992                 min_y = qMin(p1_y, min_y);
993                 max_y = qMax(p2_y, max_y);
994             }
995         }
996         buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
997     }
998 }
999
1000 void QPaintBufferEngine::drawLines(const QLineF *lines, int lineCount)
1001 {
1002 #ifdef QPAINTBUFFER_DEBUG_DRAW
1003     qDebug() << "QPaintBufferEngine: drawLinesF:" << lineCount;
1004 #endif
1005     QPaintBufferCommand *cmd =
1006         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawLineF, (qreal *) lines, 4 * lineCount, lineCount);
1007     cmd->extra = lineCount;
1008
1009     if (buffer->calculateBoundingRect) {
1010         qreal min_x = lines[0].p1().x();
1011         qreal min_y = lines[0].p1().y();
1012         qreal max_x = lines[0].p2().x();
1013         qreal max_y = lines[0].p2().y();
1014         if (min_x > max_x)
1015             qSwap(min_x, max_x);
1016         if (min_y > max_y)
1017             qSwap(min_y, max_y);
1018         for (int i=1; i < lineCount; ++i) {
1019             qreal p1_x = lines[i].p1().x();
1020             qreal p1_y = lines[i].p1().y();
1021             qreal p2_x = lines[i].p2().x();
1022             qreal p2_y = lines[i].p2().y();
1023             if (p1_x > p2_x) {
1024                 min_x = qMin(p2_x, min_x);
1025                 max_x = qMax(p1_x, max_x);
1026             } else {
1027                 min_x = qMin(p1_x, min_x);
1028                 max_x = qMax(p2_x, max_x);
1029             }
1030             if (p1_y > p2_y) {
1031                 min_y = qMin(p2_y, min_y);
1032                 max_y = qMax(p1_y, max_y);
1033             } else {
1034                 min_y = qMin(p1_y, min_y);
1035                 max_y = qMax(p2_y, max_y);
1036             }
1037         }
1038         buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
1039     }
1040 }
1041
1042 void QPaintBufferEngine::drawEllipse(const QRectF &r)
1043 {
1044 #ifdef QPAINTBUFFER_DEBUG_DRAW
1045     qDebug() << "QPaintBufferEngine: drawEllipseF:" << r;
1046 #endif
1047     buffer->addCommand(QPaintBufferPrivate::Cmd_DrawEllipseF, (qreal *) &r, 4, 1);
1048     if (buffer->calculateBoundingRect)
1049         buffer->updateBoundingRect(r);
1050 }
1051
1052 void QPaintBufferEngine::drawEllipse(const QRect &r)
1053 {
1054 #ifdef QPAINTBUFFER_DEBUG_DRAW
1055     qDebug() << "QPaintBufferEngine: drawEllipseI:" << r;
1056 #endif
1057     buffer->addCommand(QPaintBufferPrivate::Cmd_DrawEllipseI, (int *) &r, 4, 1);
1058     if (buffer->calculateBoundingRect)
1059         buffer->updateBoundingRect(r);
1060 }
1061
1062 void QPaintBufferEngine::drawPath(const QPainterPath &path)
1063 {
1064 // #ifdef QPAINTBUFFER_DEBUG_DRAW
1065 //     qDebug() << "QPaintBufferEngine: drawPath: element count:" << path.elementCount();
1066 // #endif
1067 //     // ### Path -> QVariant
1068 //     // buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPath, QVariant(path));
1069     QPaintEngineEx::drawPath(path);
1070
1071 //     if (buffer->calculateBoundingRect)
1072 //         buffer->updateBoundingRect(path.boundingRect());
1073 }
1074
1075 void QPaintBufferEngine::drawPoints(const QPoint *points, int pointCount)
1076 {
1077 #ifdef QPAINTBUFFER_DEBUG_DRAW
1078     qDebug() << "QPaintBufferEngine: drawPointsI: " << pointCount;
1079 #endif
1080     buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPointsI, (int *) points, 2 * pointCount, pointCount);
1081
1082     if (buffer->calculateBoundingRect) {
1083         int min_x = points[0].x();
1084         int min_y = points[0].y();
1085         int max_x = points[0].x()+1;
1086         int max_y = points[0].y()+1;
1087         for (int i=1; i<pointCount; ++i) {
1088             int x = points[i].x();
1089             int y = points[i].y();
1090             min_x = qMin(min_x, x);
1091             min_y = qMin(min_y, y);
1092             max_x = qMax(max_x, x+1);
1093             max_y = qMax(max_y, y+1);
1094         }
1095         buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
1096     }
1097 }
1098
1099 void QPaintBufferEngine::drawPoints(const QPointF *points, int pointCount)
1100 {
1101 #ifdef QPAINTBUFFER_DEBUG_DRAW
1102     qDebug() << "QPaintBufferEngine: drawPointsF: " << pointCount;
1103 #endif
1104     buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPointsF, (qreal *) points, 2 * pointCount, pointCount);
1105
1106     if (buffer->calculateBoundingRect) {
1107         qreal min_x = points[0].x();
1108         qreal min_y = points[0].y();
1109         qreal max_x = points[0].x()+1;
1110         qreal max_y = points[0].y()+1;
1111         for (int i=1; i<pointCount; ++i) {
1112             qreal x = points[i].x();
1113             qreal y = points[i].y();
1114             min_x = qMin(min_x, x);
1115             min_y = qMin(min_y, y);
1116             max_x = qMax(max_x, x+1);
1117             max_y = qMax(max_y, y+1);
1118         }
1119         buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
1120     }
1121 }
1122
1123 void QPaintBufferEngine::drawPolygon(const QPoint *pts, int count, PolygonDrawMode mode)
1124 {
1125 #ifdef QPAINTBUFFER_DEBUG_DRAW
1126     qDebug() << "QPaintBufferEngine: drawPolygonI: size:" << count << ", mode:" << mode;
1127 #endif
1128     if (mode == QPaintEngine::OddEvenMode || mode == QPaintEngine::WindingMode) {
1129         QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolygonI,
1130                                                       (int *) pts, 2 * count, count);
1131         cmd->extra = mode;
1132     } else if (mode == QPaintEngine::PolylineMode) {
1133         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolylineI, (int *) pts, 2 * count, count);
1134     } else {
1135         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawConvexPolygonI, (int *) pts, 2 * count, count);
1136     }
1137
1138     if (buffer->calculateBoundingRect) {
1139         int min_x = pts[0].x();
1140         int min_y = pts[0].y();
1141         int max_x = pts[0].x();
1142         int max_y = pts[0].y();
1143         for (int i=1; i<count; ++i) {
1144             int x = pts[i].x();
1145             int y = pts[i].y();
1146             min_x = qMin(min_x, x);
1147             min_y = qMin(min_y, y);
1148             max_x = qMax(max_x, x);
1149             max_y = qMax(max_y, y);
1150         }
1151         buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
1152     }
1153 }
1154
1155 void QPaintBufferEngine::drawPolygon(const QPointF *pts, int count, PolygonDrawMode mode)
1156 {
1157 #ifdef QPAINTBUFFER_DEBUG_DRAW
1158     qDebug() << "QPaintBufferEngine: drawPolygonF: size:" << count << ", mode:" << mode;
1159 #endif
1160     if (mode == QPaintEngine::OddEvenMode || mode == QPaintEngine::WindingMode) {
1161         QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolygonF,
1162                                                       (qreal *) pts, 2 * count, count);
1163         cmd->extra = mode;
1164     } else if (mode == QPaintEngine::PolylineMode) {
1165         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPolylineF, (qreal *) pts, 2 * count, count);
1166     } else {
1167         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawConvexPolygonF, (qreal *) pts, 2 * count, count);
1168     }
1169
1170     if (buffer->calculateBoundingRect) {
1171         qreal min_x = pts[0].x();
1172         qreal min_y = pts[0].y();
1173         qreal max_x = pts[0].x();
1174         qreal max_y = pts[0].y();
1175         for (int i=1; i<count; ++i) {
1176             qreal x = pts[i].x();
1177             qreal y = pts[i].y();
1178             min_x = qMin(min_x, x);
1179             min_y = qMin(min_y, y);
1180             max_x = qMax(max_x, x);
1181             max_y = qMax(max_y, y);
1182         }
1183         buffer->updateBoundingRect(QRectF(min_x, min_y, max_x - min_x, max_y - min_y));
1184     }
1185 }
1186
1187 void QPaintBufferEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
1188 {
1189 #ifdef QPAINTBUFFER_DEBUG_DRAW
1190     qDebug() << "QPaintBufferEngine: drawPixmap: src/dest rects " << r << sr;
1191 #endif
1192     QPaintBufferCommand *cmd =
1193         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPixmapRect, QVariant(pm));
1194     cmd->extra = buffer->addData((qreal *) &r, 4);
1195     buffer->addData((qreal *) &sr, 4);
1196     if (buffer->calculateBoundingRect)
1197         buffer->updateBoundingRect(r);
1198 }
1199
1200 void QPaintBufferEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
1201 {
1202 #ifdef QPAINTBUFFER_DEBUG_DRAW
1203     qDebug() << "QPaintBufferEngine: drawPixmap: pos:" << pos;
1204 #endif
1205     QPaintBufferCommand *cmd =
1206         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPixmapPos, QVariant(pm));
1207     cmd->extra = buffer->addData((qreal *) &pos, 2);
1208     if (buffer->calculateBoundingRect)
1209         buffer->updateBoundingRect(QRectF(pos, pm.size()));
1210 }
1211
1212 static inline QImage qpaintbuffer_storable_image(const QImage &src)
1213 {
1214     QImageData *d = const_cast<QImage &>(src).data_ptr();
1215     return d->own_data ? src : src.copy();
1216 }
1217
1218 void QPaintBufferEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
1219                                    Qt::ImageConversionFlags /*flags */)
1220 {
1221 #ifdef QPAINTBUFFER_DEBUG_DRAW
1222     qDebug() << "QPaintBufferEngine: drawImage: src/dest rects " << r << sr;
1223 #endif
1224     QPaintBufferCommand *cmd =
1225         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawImageRect,
1226                            QVariant(qpaintbuffer_storable_image(image)));
1227     cmd->extra = buffer->addData((qreal *) &r, 4);
1228     buffer->addData((qreal *) &sr, 4);
1229     // ### flags...
1230     if (buffer->calculateBoundingRect)
1231         buffer->updateBoundingRect(r);
1232 }
1233
1234 void QPaintBufferEngine::drawImage(const QPointF &pos, const QImage &image)
1235 {
1236 #ifdef QPAINTBUFFER_DEBUG_DRAW
1237     qDebug() << "QPaintBufferEngine: drawImage: pos:" << pos;
1238 #endif
1239     QPaintBufferCommand *cmd =
1240         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawImagePos,
1241                            QVariant(qpaintbuffer_storable_image(image)));
1242     cmd->extra = buffer->addData((qreal *) &pos, 2);
1243     if (buffer->calculateBoundingRect)
1244         buffer->updateBoundingRect(QRectF(pos, image.size()));
1245 }
1246
1247 void QPaintBufferEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &s)
1248 {
1249 #ifdef QPAINTBUFFER_DEBUG_DRAW
1250     qDebug() << "QPaintBufferEngine: drawTiledPixmap: src rect/offset:" << r << s;
1251 #endif
1252     QPaintBufferCommand *cmd =
1253         buffer->addCommand(QPaintBufferPrivate::Cmd_DrawTiledPixmap, QVariant(pm));
1254     cmd->extra = buffer->addData((qreal *) &r, 4);
1255     buffer->addData((qreal *) &s, 2);
1256     if (buffer->calculateBoundingRect)
1257         buffer->updateBoundingRect(r);
1258 }
1259
1260 void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem)
1261 {
1262     QVariantList variants;
1263
1264     variants << QVariant(staticTextItem->font);
1265     for (int i=0; i<staticTextItem->numGlyphs; ++i) {
1266         variants.append(staticTextItem->glyphs[i]);
1267         variants.append(staticTextItem->glyphPositions[i].toPointF());
1268     }
1269
1270     buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants));
1271 }
1272
1273 void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti)
1274 {
1275 #ifdef QPAINTBUFFER_DEBUG_DRAW
1276     qDebug() << "QPaintBufferEngine: drawTextItem: pos:" << pos << ti.text();
1277 #endif
1278     if (m_stream_raw_text_items) {
1279         QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawTextItem, QVariant::fromValue<void *>(new QTextItemIntCopy(ti)));
1280
1281         QFont font(ti.font());
1282         font.setUnderline(false);
1283         font.setStrikeOut(false);
1284         font.setOverline(false);
1285
1286         const QTextItemInt &si = static_cast<const QTextItemInt &>(ti);
1287         qreal justificationWidth = 0;
1288         if (si.justified)
1289             justificationWidth = si.width.toReal();
1290         int renderFlags = ti.renderFlags();
1291         qreal scaleFactor = font.d->dpi/qreal(qt_defaultDpiY());
1292
1293         buffer->addData(QVariant(font));
1294         cmd->extra = buffer->addData((qreal *) &pos, 2);
1295         buffer->addData((qreal *) &justificationWidth, 1);
1296         buffer->addData((qreal *) &scaleFactor, 1);
1297         cmd->offset2 = buffer->addData((int *) &renderFlags, 1);
1298     } else {
1299         QList<QVariant> variants;
1300         variants << QVariant(ti.font()) << QVariant(ti.text());
1301         QPaintBufferCommand *cmd = buffer->addCommand(QPaintBufferPrivate::Cmd_DrawText, QVariant(variants));
1302         cmd->extra = buffer->addData((qreal *) &pos, 2);
1303     }
1304
1305     if (buffer->calculateBoundingRect)
1306         buffer->updateBoundingRect(QRectF(pos, QSize(ti.width(), ti.ascent() + ti.descent() + 1)));
1307 }
1308
1309
1310 void QPaintBufferEngine::setState(QPainterState *s)
1311 {
1312     Q_D(QPaintBufferEngine);
1313     if (m_begin_detected) {
1314 #ifdef QPAINTBUFFER_DEBUG_DRAW
1315             qDebug() << "QPaintBufferEngine: setState: begin, ignoring.";
1316 #endif
1317         m_begin_detected = false;
1318     } else if (m_save_detected) {
1319 #ifdef QPAINTBUFFER_DEBUG_DRAW
1320         qDebug() << "QPaintBufferEngine: setState: save.";
1321 #endif
1322         m_save_detected = false;
1323         buffer->addCommand(QPaintBufferPrivate::Cmd_Save);
1324     } else {
1325 #ifdef QPAINTBUFFER_DEBUG_DRAW
1326         qDebug() << "QPaintBufferEngine: setState: restore.";
1327 #endif
1328         buffer->addCommand(QPaintBufferPrivate::Cmd_Restore);
1329     }
1330
1331     d->last = s->matrix;
1332
1333     QPaintEngineEx::setState(s);
1334 }
1335
1336
1337 /***********************************************************************
1338  *
1339  * class QPaintBufferPlayback_Painter
1340  *
1341  */
1342
1343 // QFakeDevice is used to create fonts with a custom DPI
1344 //
1345 class QFakeDevice : public QPaintDevice
1346 {
1347 public:
1348     QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); }
1349     void setDpiX(int dpi) { dpi_x = dpi; }
1350     void setDpiY(int dpi) { dpi_y = dpi; }
1351     QPaintEngine *paintEngine() const { return 0; }
1352     int metric(PaintDeviceMetric m) const
1353     {
1354         switch(m) {
1355             case PdmPhysicalDpiX:
1356             case PdmDpiX:
1357                 return dpi_x;
1358             case PdmPhysicalDpiY:
1359             case PdmDpiY:
1360                 return dpi_y;
1361             default:
1362                 return QPaintDevice::metric(m);
1363         }
1364     }
1365
1366 private:
1367     int dpi_x;
1368     int dpi_y;
1369 };
1370
1371
1372 void QPainterReplayer::setupTransform(QPainter *_painter)
1373 {
1374     painter = _painter;
1375     m_world_matrix = painter->transform();
1376     m_world_matrix.scale(qreal(painter->device()->logicalDpiX()) / qreal(qt_defaultDpiX()),
1377                          qreal(painter->device()->logicalDpiY()) / qreal(qt_defaultDpiY()));
1378     painter->setTransform(m_world_matrix);
1379 }
1380
1381 void QPainterReplayer::processCommands(const QPaintBuffer &buffer, QPainter *p, int begin, int end)
1382 {
1383     d = buffer.d_ptr;
1384     painter = p;
1385
1386     for (int cmdIndex = begin; cmdIndex < end; ++cmdIndex) {
1387         const QPaintBufferCommand &cmd = d->commands.at(cmdIndex);
1388         process(cmd);
1389     }
1390 }
1391
1392 void QPaintBuffer::beginNewFrame()
1393 {
1394     if (!d_ptr->commands.isEmpty())
1395         d_ptr->frames << d_ptr->commands.size();
1396 }
1397
1398 int QPaintBuffer::numFrames() const
1399 {
1400     return d_ptr->frames.size() + 1;
1401 }
1402
1403 void QPainterReplayer::process(const QPaintBufferCommand &cmd)
1404 {
1405     switch (cmd.id) {
1406     case QPaintBufferPrivate::Cmd_Save: {
1407 #ifdef QPAINTBUFFER_DEBUG_DRAW
1408         qDebug() << " -> Cmd_Save";
1409 #endif
1410         painter->save();
1411         break; }
1412
1413     case QPaintBufferPrivate::Cmd_Restore: {
1414 #ifdef QPAINTBUFFER_DEBUG_DRAW
1415         qDebug() << " -> Cmd_Restore";
1416 #endif
1417         painter->restore();
1418         break; }
1419
1420     case QPaintBufferPrivate::Cmd_SetPen: {
1421         QPen pen = qvariant_cast<QPen>(d->variants.at(cmd.offset));
1422 #ifdef QPAINTBUFFER_DEBUG_DRAW
1423         qDebug() << " -> Cmd_SetPen: " << pen;
1424 #endif
1425         painter->setPen(pen);
1426         break; }
1427
1428     case QPaintBufferPrivate::Cmd_SetBrush: {
1429         QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.offset));
1430 #ifdef QPAINTBUFFER_DEBUG_DRAW
1431         qDebug() << " -> Cmd_SetBrush: " << brush;
1432 #endif
1433         painter->setBrush(brush);
1434         break; }
1435
1436     case QPaintBufferPrivate::Cmd_SetBrushOrigin: {
1437 #ifdef QPAINTBUFFER_DEBUG_DRAW
1438         qDebug() << " -> Cmd_SetBrushOrigin: " << d->variants.at(cmd.offset).toPointF();
1439 #endif
1440         painter->setBrushOrigin(d->variants.at(cmd.offset).toPointF());
1441         break; }
1442
1443     case QPaintBufferPrivate::Cmd_SetTransform: {
1444         QTransform xform = qvariant_cast<QTransform>(d->variants.at(cmd.offset));
1445 #ifdef QPAINTBUFFER_DEBUG_DRAW
1446         qDebug() << " -> Cmd_SetTransform, offset: " << cmd.offset << xform;
1447 #endif
1448         painter->setTransform(xform * m_world_matrix);
1449         break; }
1450
1451     case QPaintBufferPrivate::Cmd_Translate: {
1452         QPointF delta(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
1453 #ifdef QPAINTBUFFER_DEBUG_DRAW
1454         qDebug() << " -> Cmd_Translate, offset: " << cmd.offset << delta;
1455 #endif
1456         painter->translate(delta.x(), delta.y());
1457         return;
1458     }
1459
1460     case QPaintBufferPrivate::Cmd_SetCompositionMode: {
1461         QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra;
1462 #ifdef QPAINTBUFFER_DEBUG_DRAW
1463         qDebug() << " -> Cmd_SetCompositionMode, mode: " << mode;
1464 #endif
1465         painter->setCompositionMode(mode);
1466         break; }
1467
1468     case QPaintBufferPrivate::Cmd_SetRenderHints: {
1469 #ifdef QPAINTBUFFER_DEBUG_DRAW
1470         qDebug() << " -> Cmd_SetRenderHints, hints: " << cmd.extra;
1471 #endif
1472         QPainter::RenderHints ph = painter->renderHints();
1473         QPainter::RenderHints nh = (QPainter::RenderHints) cmd.extra;
1474         QPainter::RenderHints xored = ph ^ nh;
1475         if (xored & QPainter::Antialiasing)
1476             painter->setRenderHint(QPainter::Antialiasing, nh & QPainter::Antialiasing);
1477         if (xored & QPainter::HighQualityAntialiasing)
1478             painter->setRenderHint(QPainter::HighQualityAntialiasing, nh & QPainter::HighQualityAntialiasing);
1479         if (xored & QPainter::TextAntialiasing)
1480             painter->setRenderHint(QPainter::TextAntialiasing, nh & QPainter::TextAntialiasing);
1481         if (xored & QPainter::SmoothPixmapTransform)
1482             painter->setRenderHint(QPainter::SmoothPixmapTransform, nh & QPainter::SmoothPixmapTransform);
1483         if (xored & QPainter::NonCosmeticDefaultPen)
1484             painter->setRenderHint(QPainter::NonCosmeticDefaultPen, nh & QPainter::NonCosmeticDefaultPen);
1485         break; }
1486
1487     case QPaintBufferPrivate::Cmd_SetOpacity: {
1488 #ifdef QPAINTBUFFER_DEBUG_DRAW
1489         qDebug() << " -> Cmd_SetOpacity: " << d->variants.at(cmd.offset).toDouble();
1490 #endif
1491         painter->setOpacity(d->variants.at(cmd.offset).toDouble());
1492         break; }
1493
1494     case QPaintBufferPrivate::Cmd_SetBackgroundMode: {
1495 #ifdef QPAINTBUFFER_DEBUG_DRAW
1496         qDebug() << " -> Cmd_SetBackgroundMode: " << cmd.extra;
1497 #endif
1498         painter->setBackgroundMode((Qt::BGMode)cmd.extra);
1499         break; }
1500
1501     case QPaintBufferPrivate::Cmd_DrawVectorPath: {
1502 #ifdef QPAINTBUFFER_DEBUG_DRAW
1503         qDebug() << " -> Cmd_DrawVectorPath: size: " << cmd.size
1504 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
1505                  << "pts/elms:" << cmd.offset << cmd.offset2;
1506 #endif
1507         QVectorPathCmd path(d, cmd);
1508         painter->drawPath(path().convertToPainterPath());
1509         break; }
1510
1511     case QPaintBufferPrivate::Cmd_StrokeVectorPath: {
1512         QPen pen = qvariant_cast<QPen>(d->variants.at(cmd.extra));
1513 #ifdef QPAINTBUFFER_DEBUG_DRAW
1514         qDebug() << " -> Cmd_StrokeVectorPath: size: " << cmd.size
1515 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
1516                  << "pts/elms:" << cmd.offset << cmd.offset2;
1517 #endif
1518         QVectorPathCmd path(d, cmd);
1519         painter->strokePath(path().convertToPainterPath(), pen);
1520         break; }
1521
1522     case QPaintBufferPrivate::Cmd_FillVectorPath: {
1523         QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra));
1524 #ifdef QPAINTBUFFER_DEBUG_DRAW
1525         qDebug() << " -> Cmd_FillVectorPath: size: " << cmd.size
1526 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
1527                  << "pts/elms:" << cmd.offset << cmd.offset2 << brush;
1528 #endif
1529         QVectorPathCmd path(d, cmd);
1530         painter->fillPath(path().convertToPainterPath(), brush);
1531         break; }
1532
1533     case QPaintBufferPrivate::Cmd_DrawPolygonF: {
1534 #ifdef QPAINTBUFFER_DEBUG_DRAW
1535         qDebug() << " -> Cmd_DrawPolygonF, offset: " << cmd.offset << " size: " << cmd.size
1536                  << " mode: " << cmd.extra
1537                  << d->floats.at(cmd.offset)
1538                  << d->floats.at(cmd.offset+1);
1539 #endif
1540         Qt::FillRule fill = (QPaintEngine::PolygonDrawMode) cmd.extra == QPaintEngine::OddEvenMode
1541                             ? Qt::OddEvenFill : Qt::WindingFill;
1542         painter->drawPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size, fill);
1543         break; }
1544
1545     case QPaintBufferPrivate::Cmd_DrawPolygonI: {
1546 #ifdef QPAINTBUFFER_DEBUG_DRAW
1547         qDebug() << " -> Cmd_DrawPolygonI, offset: " << cmd.offset << " size: " << cmd.size
1548                  << " mode: " << cmd.extra
1549                  << d->ints.at(cmd.offset)
1550                  << d->ints.at(cmd.offset+1);
1551 #endif
1552         Qt::FillRule fill = (QPaintEngine::PolygonDrawMode) cmd.extra == QPaintEngine::OddEvenMode
1553                             ? Qt::OddEvenFill : Qt::WindingFill;
1554         painter->drawPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size, fill);
1555         break; }
1556
1557     case QPaintBufferPrivate::Cmd_DrawPolylineF: {
1558 #ifdef QPAINTBUFFER_DEBUG_DRAW
1559         qDebug() << " -> Cmd_DrawPolylineF, offset: " << cmd.offset << " size: " << cmd.size;
1560 #endif
1561         painter->drawPolyline((QPointF *) (d->floats.constData() + cmd.offset), cmd.size);
1562         break; }
1563
1564     case QPaintBufferPrivate::Cmd_DrawPolylineI: {
1565 #ifdef QPAINTBUFFER_DEBUG_DRAW
1566         qDebug() << " -> Cmd_DrawPolylineI, offset: " << cmd.offset << " size: " << cmd.size;
1567 #endif
1568         painter->drawPolyline((QPoint *) (d->ints.constData() + cmd.offset), cmd.size);
1569         break; }
1570
1571     case QPaintBufferPrivate::Cmd_DrawConvexPolygonF: {
1572 #ifdef QPAINTBUFFER_DEBUG_DRAW
1573         qDebug() << " -> Cmd_DrawConvexPolygonF, offset: " << cmd.offset << " size: " << cmd.size;
1574 #endif
1575         painter->drawConvexPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size);
1576         break; }
1577
1578     case QPaintBufferPrivate::Cmd_DrawConvexPolygonI: {
1579 #ifdef QPAINTBUFFER_DEBUG_DRAW
1580         qDebug() << " -> Cmd_DrawConvexPolygonI, offset: " << cmd.offset << " size: " << cmd.size;
1581 #endif
1582         painter->drawConvexPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size);
1583         break; }
1584
1585     case QPaintBufferPrivate::Cmd_DrawEllipseF: {
1586 #ifdef QPAINTBUFFER_DEBUG_DRAW
1587         qDebug() << " -> Cmd_DrawEllipseF, offset: " << cmd.offset;
1588 #endif
1589         painter->drawEllipse(*(QRectF *)(d->floats.constData() + cmd.offset));
1590         break; }
1591
1592     case QPaintBufferPrivate::Cmd_DrawEllipseI: {
1593 #ifdef QPAINTBUFFER_DEBUG_DRAW
1594         qDebug() << " -> Cmd_DrawEllipseI, offset: " << cmd.offset;
1595 #endif
1596         painter->drawEllipse(*(QRect *)(d->ints.constData() + cmd.offset));
1597         break; }
1598
1599     case QPaintBufferPrivate::Cmd_DrawLineF: {
1600 #ifdef QPAINTBUFFER_DEBUG_DRAW
1601         qDebug() << " -> Cmd_DrawLineF, offset: " << cmd.offset << " size: " << cmd.size;
1602 #endif
1603         painter->drawLines((QLineF *)(d->floats.constData() + cmd.offset), cmd.size);
1604         break; }
1605
1606     case QPaintBufferPrivate::Cmd_DrawLineI: {
1607 #ifdef QPAINTBUFFER_DEBUG_DRAW
1608         qDebug() << " -> Cmd_DrawLineI, offset: " << cmd.offset << " size: " << cmd.size;
1609 #endif
1610         painter->drawLines((QLine *)(d->ints.constData() + cmd.offset), cmd.size);
1611         break; }
1612
1613     case QPaintBufferPrivate::Cmd_DrawPointsF: {
1614 #ifdef QPAINTBUFFER_DEBUG_DRAW
1615         qDebug() << " -> Cmd_DrawPointsF, offset: " << cmd.offset << " size: " << cmd.size;
1616 #endif
1617         painter->drawPoints((QPointF *)(d->floats.constData() + cmd.offset), cmd.size);
1618         break; }
1619
1620     case QPaintBufferPrivate::Cmd_DrawPointsI: {
1621 #ifdef QPAINTBUFFER_DEBUG_DRAW
1622         qDebug() << " -> Cmd_DrawPointsI, offset: " << cmd.offset << " size: " << cmd.size;
1623 #endif
1624         painter->drawPoints((QPoint *)(d->ints.constData() + cmd.offset), cmd.size);
1625         break; }
1626
1627     case QPaintBufferPrivate::Cmd_DrawPixmapRect: {
1628         QPixmap pm(d->variants.at(cmd.offset).value<QPixmap>());
1629         QRectF r(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1),
1630                  d->floats.at(cmd.extra+2), d->floats.at(cmd.extra+3));
1631
1632         QRectF sr(d->floats.at(cmd.extra+4), d->floats.at(cmd.extra+5),
1633                   d->floats.at(cmd.extra+6), d->floats.at(cmd.extra+7));
1634 #ifdef QPAINTBUFFER_DEBUG_DRAW
1635         qDebug() << " -> Cmd_DrawPixmapRect:" << r << sr;
1636 #endif
1637         painter->drawPixmap(r, pm, sr);
1638         break; }
1639
1640     case QPaintBufferPrivate::Cmd_DrawPixmapPos: {
1641         QPixmap pm(d->variants.at(cmd.offset).value<QPixmap>());
1642         QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
1643 #ifdef QPAINTBUFFER_DEBUG_DRAW
1644         qDebug() << " -> Cmd_DrawPixmapPos:" << pos;
1645 #endif
1646         painter->drawPixmap(pos, pm);
1647         break; }
1648
1649     case QPaintBufferPrivate::Cmd_DrawTiledPixmap: {
1650         QPixmap pm(d->variants.at(cmd.offset).value<QPixmap>());
1651         QRectF r(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1),
1652                  d->floats.at(cmd.extra+2), d->floats.at(cmd.extra+3));
1653
1654         QPointF offset(d->floats.at(cmd.extra+4), d->floats.at(cmd.extra+5));
1655 #ifdef QPAINTBUFFER_DEBUG_DRAW
1656         qDebug() << " -> Cmd_DrawTiledPixmap:" << r << offset;
1657 #endif
1658         painter->drawTiledPixmap(r, pm, offset);
1659         break; }
1660
1661     case QPaintBufferPrivate::Cmd_DrawImageRect: {
1662         QImage image(d->variants.at(cmd.offset).value<QImage>());
1663         QRectF r(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1),
1664                  d->floats.at(cmd.extra+2), d->floats.at(cmd.extra+3));
1665         QRectF sr(d->floats.at(cmd.extra+4), d->floats.at(cmd.extra+5),
1666                   d->floats.at(cmd.extra+6), d->floats.at(cmd.extra+7));
1667 #ifdef QPAINTBUFFER_DEBUG_DRAW
1668         qDebug() << " -> Cmd_DrawImageRect:" << r << sr;
1669 #endif
1670         painter->drawImage(r, image, sr);
1671         break; }
1672
1673     case QPaintBufferPrivate::Cmd_DrawImagePos: {
1674         QImage image(d->variants.at(cmd.offset).value<QImage>());
1675         QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
1676 #ifdef QPAINTBUFFER_DEBUG_DRAW
1677         qDebug() << " -> Cmd_DrawImagePos:" << pos;
1678 #endif
1679         painter->drawImage(pos, image);
1680         break; }
1681
1682     case QPaintBufferPrivate::Cmd_DrawRectF: {
1683 #ifdef QPAINTBUFFER_DEBUG_DRAW
1684         qDebug() << " -> Cmd_DrawRectF, offset: " << cmd.offset;
1685 #endif
1686         painter->drawRects((QRectF *)(d->floats.constData() + cmd.offset), cmd.size);
1687         break; }
1688
1689     case QPaintBufferPrivate::Cmd_DrawRectI: {
1690 #ifdef QPAINTBUFFER_DEBUG_DRAW
1691         qDebug() << " -> Cmd_DrawRectI, offset: " << cmd.offset;
1692 #endif
1693         painter->drawRects((QRect *)(d->ints.constData() + cmd.offset), cmd.size);
1694         break; }
1695
1696     case QPaintBufferPrivate::Cmd_FillRectBrush: {
1697         QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra));
1698         QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset);
1699 #ifdef QPAINTBUFFER_DEBUG_DRAW
1700         qDebug() << " -> Cmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush;
1701 #endif
1702         painter->fillRect(*rect, brush);
1703         break; }
1704
1705     case QPaintBufferPrivate::Cmd_FillRectColor: {
1706         QColor color = qvariant_cast<QColor>(d->variants.at(cmd.extra));
1707         QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset);
1708 #ifdef QPAINTBUFFER_DEBUG_DRAW
1709         qDebug() << " -> Cmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color;
1710 #endif
1711         painter->fillRect(*rect, color);
1712         break; }
1713
1714     case QPaintBufferPrivate::Cmd_SetClipEnabled: {
1715         bool clipEnabled = d->variants.at(cmd.offset).toBool();
1716 #ifdef QPAINTBUFFER_DEBUG_DRAW
1717         qDebug() << " -> Cmd_SetClipEnabled:" << clipEnabled;
1718 #endif
1719         painter->setClipping(clipEnabled);
1720         break; }
1721
1722     case QPaintBufferPrivate::Cmd_ClipVectorPath: {
1723         QVectorPathCmd path(d, cmd);
1724 #ifdef QPAINTBUFFER_DEBUG_DRAW
1725         qDebug() << " -> Cmd_ClipVectorPath:" << path().elementCount();
1726 #endif
1727         painter->setClipPath(path().convertToPainterPath(), Qt::ClipOperation(cmd.extra));
1728         break; }
1729
1730
1731     case QPaintBufferPrivate::Cmd_ClipRect: {
1732         QRect rect(QPoint(d->ints.at(cmd.offset), d->ints.at(cmd.offset + 1)),
1733                    QPoint(d->ints.at(cmd.offset + 2), d->ints.at(cmd.offset + 3)));
1734 #ifdef QPAINTBUFFER_DEBUG_DRAW
1735         qDebug() << " -> Cmd_ClipRect:" << rect << cmd.extra;
1736 #endif
1737         painter->setClipRect(rect, Qt::ClipOperation(cmd.extra));
1738         break; }
1739
1740     case QPaintBufferPrivate::Cmd_ClipRegion: {
1741         QRegion region(d->variants.at(cmd.offset).value<QRegion>());
1742 #ifdef QPAINTBUFFER_DEBUG_DRAW
1743         qDebug() << " -> Cmd_ClipRegion:" << region.boundingRect() << cmd.extra;
1744 #endif
1745         painter->setClipRegion(region, Qt::ClipOperation(cmd.extra));
1746         break; }
1747         
1748 #if !defined(QT_NO_RAWFONT)
1749     case QPaintBufferPrivate::Cmd_DrawStaticText: {
1750             
1751             QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>());
1752             
1753             QFont font = variants.at(0).value<QFont>();
1754
1755             QVector<quint32> glyphIndexes;
1756             QVector<QPointF> positions;
1757
1758             for (int i=0; i<(variants.size() - 1) / 2; ++i) {
1759                 glyphIndexes.append(variants.at(i*2 + 1).toUInt());
1760                 positions.append(variants.at(i*2 + 2).toPointF());
1761             }
1762
1763             painter->setFont(font);
1764
1765             QRawFont rawFont;
1766             QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont);
1767             QFontPrivate *fontD = QFontPrivate::get(font);
1768             rawFontD->fontEngine = fontD->engineForScript(QUnicodeTables::Common);
1769             rawFontD->fontEngine->ref.ref();
1770
1771             QGlyphRun glyphs;
1772             glyphs.setRawFont(rawFont);
1773             glyphs.setGlyphIndexes(glyphIndexes);
1774             glyphs.setPositions(positions);
1775
1776             painter->drawGlyphRun(QPointF(), glyphs);
1777             break;
1778     }
1779 #endif
1780
1781     case QPaintBufferPrivate::Cmd_DrawText: {
1782         QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
1783         QList<QVariant> variants(d->variants.at(cmd.offset).value<QList<QVariant> >());
1784
1785         QFont font(variants.at(0).value<QFont>());
1786         QString text(variants.at(1).value<QString>());
1787
1788         painter->setFont(font);
1789         painter->drawText(pos, text);
1790         break; }
1791
1792     case QPaintBufferPrivate::Cmd_DrawTextItem: {
1793         QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
1794         QTextItemIntCopy *tiCopy = reinterpret_cast<QTextItemIntCopy *>(qvariant_cast<void *>(d->variants.at(cmd.offset)));
1795         QTextItemInt &ti = (*tiCopy)();
1796         QString text(ti.text());
1797
1798         QFont font(ti.font());
1799         font.setUnderline(false);
1800         font.setStrikeOut(false);
1801         font.setOverline(false);
1802
1803         const QTextItemInt &si = static_cast<const QTextItemInt &>(ti);
1804         qreal justificationWidth = 0;
1805         if (si.justified)
1806             justificationWidth = si.width.toReal();
1807         qreal scaleFactor = font.d->dpi/qreal(qt_defaultDpiY());
1808
1809 #ifdef QPAINTBUFFER_DEBUG_DRAW
1810         qDebug() << " -> Cmd_DrawTextItem:" << pos << " " << text << " " << scaleFactor;
1811 #endif
1812
1813         if (scaleFactor != 1.0) {
1814             QFont fnt(font);
1815             QFakeDevice fake;
1816             fake.setDpiX(qRound(scaleFactor*qt_defaultDpiX()));
1817             fake.setDpiY(qRound(scaleFactor*qt_defaultDpiY()));
1818             font = QFont(fnt, &fake);
1819         }
1820
1821         int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight;
1822         QSizeF size(1, 1);
1823         if (justificationWidth > 0) {
1824             size.setWidth(justificationWidth);
1825             flags |= Qt::TextJustificationForced;
1826             flags |= Qt::AlignJustify;
1827         }
1828
1829         QFontMetrics fm(font);
1830         QPointF pt(pos.x(), pos.y() - fm.ascent());
1831         qt_format_text(font, QRectF(pt, size), flags, /*opt*/0,
1832                        text, /*brect=*/0, /*tabstops=*/0, /*...*/0, /*tabarraylen=*/0, painter);
1833         break; }
1834     case QPaintBufferPrivate::Cmd_SystemStateChanged: {
1835         QRegion systemClip(d->variants.at(cmd.offset).value<QRegion>());
1836
1837 #ifdef QPAINTBUFFER_DEBUG_DRAW
1838         qDebug() << " -> Cmd_SystemStateChanged:" << systemClip;
1839 #endif
1840
1841         painter->paintEngine()->setSystemClip(systemClip);
1842         painter->paintEngine()->d_ptr->systemStateChanged();
1843         break; }
1844     }
1845 }
1846
1847 void QPaintEngineExReplayer::process(const QPaintBufferCommand &cmd)
1848 {
1849     Q_ASSERT(painter->paintEngine()->isExtended());
1850     QPaintEngineEx *xengine = static_cast<QPaintEngineEx *>(painter->paintEngine());
1851
1852     switch (cmd.id) {
1853     case QPaintBufferPrivate::Cmd_SetBrushOrigin: {
1854 #ifdef QPAINTBUFFER_DEBUG_DRAW
1855         qDebug() << " -> ExCmd_SetBrushOrigin: " << d->variants.at(cmd.offset).toPointF();
1856 #endif
1857         xengine->state()->brushOrigin = d->variants.at(cmd.offset).toPointF();
1858         xengine->brushOriginChanged();
1859         break; }
1860
1861     case QPaintBufferPrivate::Cmd_SetCompositionMode: {
1862         QPainter::CompositionMode mode = (QPainter::CompositionMode) cmd.extra;
1863 #ifdef QPAINTBUFFER_DEBUG_DRAW
1864         qDebug() << " -> ExCmd_SetCompositionMode, mode: " << mode;
1865 #endif
1866         xengine->state()->composition_mode = mode;
1867         xengine->compositionModeChanged();
1868         break; }
1869
1870     case QPaintBufferPrivate::Cmd_SetOpacity: {
1871 #ifdef QPAINTBUFFER_DEBUG_DRAW
1872         qDebug() << " -> ExCmd_SetOpacity: " << d->variants.at(cmd.offset).toDouble();
1873 #endif
1874         xengine->state()->opacity = d->variants.at(cmd.offset).toDouble();
1875         xengine->opacityChanged();
1876         break; }
1877
1878     case QPaintBufferPrivate::Cmd_DrawVectorPath: {
1879 #ifdef QPAINTBUFFER_DEBUG_DRAW
1880         qDebug() << " -> ExCmd_DrawVectorPath: size: " << cmd.size
1881 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
1882                  << "pts/elms:" << cmd.offset << cmd.offset2;
1883 #endif
1884         QVectorPathCmd path(d, cmd);
1885         xengine->draw(path());
1886         break; }
1887
1888     case QPaintBufferPrivate::Cmd_StrokeVectorPath: {
1889         QPen pen = qvariant_cast<QPen>(d->variants.at(cmd.extra));
1890 #ifdef QPAINTBUFFER_DEBUG_DRAW
1891         qDebug() << " -> ExCmd_StrokeVectorPath: size: " << cmd.size
1892 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
1893                  << "pts/elms:" << cmd.offset << cmd.offset2;
1894 #endif
1895         QVectorPathCmd path(d, cmd);
1896         xengine->stroke(path(), pen);
1897         break; }
1898
1899     case QPaintBufferPrivate::Cmd_FillVectorPath: {
1900         QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra));
1901 #ifdef QPAINTBUFFER_DEBUG_DRAW
1902         qDebug() << " -> ExCmd_FillVectorPath: size: " << cmd.size
1903 //                 << ", hints:" << d->ints[cmd.offset2+cmd.size]
1904                  << "pts/elms:" << cmd.offset << cmd.offset2 << brush;
1905 #endif
1906         QVectorPathCmd path(d, cmd);
1907         xengine->fill(path(), brush);
1908         break; }
1909
1910     case QPaintBufferPrivate::Cmd_FillRectBrush: {
1911         QBrush brush = qvariant_cast<QBrush>(d->variants.at(cmd.extra));
1912         QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset);
1913 #ifdef QPAINTBUFFER_DEBUG_DRAW
1914         qDebug() << " -> ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " brush: " << brush;
1915 #endif
1916         xengine->fillRect(*rect, brush);
1917         break; }
1918
1919     case QPaintBufferPrivate::Cmd_FillRectColor: {
1920         QColor color = qvariant_cast<QColor>(d->variants.at(cmd.extra));
1921         QRectF *rect = (QRectF *)(d->floats.constData() + cmd.offset);
1922 #ifdef QPAINTBUFFER_DEBUG_DRAW
1923         qDebug() << " -> ExCmd_FillRectBrush, offset: " << cmd.offset << " rect: " << *rect << " color: " << color;
1924 #endif
1925         xengine->fillRect(*rect, color);
1926         break; }
1927
1928     case QPaintBufferPrivate::Cmd_DrawPolygonF: {
1929 #ifdef QPAINTBUFFER_DEBUG_DRAW
1930         qDebug() << " -> ExCmd_DrawPolygonF, offset: " << cmd.offset << " size: " << cmd.size
1931                  << " mode: " << cmd.extra
1932                  << d->floats.at(cmd.offset)
1933                  << d->floats.at(cmd.offset+1);
1934 #endif
1935         xengine->drawPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size,
1936                              (QPaintEngine::PolygonDrawMode) cmd.extra);
1937         break; }
1938
1939     case QPaintBufferPrivate::Cmd_DrawPolygonI: {
1940 #ifdef QPAINTBUFFER_DEBUG_DRAW
1941         qDebug() << " -> ExCmd_DrawPolygonI, offset: " << cmd.offset << " size: " << cmd.size
1942                  << " mode: " << cmd.extra
1943                  << d->ints.at(cmd.offset)
1944                  << d->ints.at(cmd.offset+1);
1945 #endif
1946         xengine->drawPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size,
1947                              (QPaintEngine::PolygonDrawMode) cmd.extra);
1948         break; }
1949
1950     case QPaintBufferPrivate::Cmd_DrawEllipseF: {
1951 #ifdef QPAINTBUFFER_DEBUG_DRAW
1952         qDebug() << " -> ExCmd_DrawEllipseF, offset: " << cmd.offset;
1953 #endif
1954         xengine->drawEllipse(*(QRectF *)(d->floats.constData() + cmd.offset));
1955         break; }
1956
1957     case QPaintBufferPrivate::Cmd_DrawEllipseI: {
1958 #ifdef QPAINTBUFFER_DEBUG_DRAW
1959         qDebug() << " -> ExCmd_DrawEllipseI, offset: " << cmd.offset;
1960 #endif
1961         xengine->drawEllipse(*(QRect *)(d->ints.constData() + cmd.offset));
1962         break; }
1963
1964     case QPaintBufferPrivate::Cmd_DrawLineF: {
1965 #ifdef QPAINTBUFFER_DEBUG_DRAW
1966         qDebug() << " -> ExCmd_DrawLineF, offset: " << cmd.offset << " size: " << cmd.size;
1967 #endif
1968         xengine->drawLines((QLineF *)(d->floats.constData() + cmd.offset), cmd.size);
1969         break; }
1970
1971     case QPaintBufferPrivate::Cmd_DrawLineI: {
1972 #ifdef QPAINTBUFFER_DEBUG_DRAW
1973         qDebug() << " -> ExCmd_DrawLineI, offset: " << cmd.offset << " size: " << cmd.size;
1974 #endif
1975         xengine->drawLines((QLine *)(d->ints.constData() + cmd.offset), cmd.size);
1976         break; }
1977
1978     case QPaintBufferPrivate::Cmd_DrawPointsF: {
1979 #ifdef QPAINTBUFFER_DEBUG_DRAW
1980         qDebug() << " -> ExCmd_DrawPointsF, offset: " << cmd.offset << " size: " << cmd.size;
1981 #endif
1982         xengine->drawPoints((QPointF *)(d->floats.constData() + cmd.offset), cmd.size);
1983         break; }
1984
1985     case QPaintBufferPrivate::Cmd_DrawPointsI: {
1986 #ifdef QPAINTBUFFER_DEBUG_DRAW
1987         qDebug() << " -> ExCmd_DrawPointsI, offset: " << cmd.offset << " size: " << cmd.size;
1988 #endif
1989         xengine->drawPoints((QPoint *)(d->ints.constData() + cmd.offset), cmd.size);
1990         break; }
1991
1992     case QPaintBufferPrivate::Cmd_DrawPolylineF: {
1993 #ifdef QPAINTBUFFER_DEBUG_DRAW
1994         qDebug() << " -> ExCmd_DrawPolylineF, offset: " << cmd.offset << " size: " << cmd.size;
1995 #endif
1996         xengine->drawPolygon((QPointF *) (d->floats.constData() + cmd.offset), cmd.size, QPaintEngine::PolylineMode);
1997         break; }
1998
1999     case QPaintBufferPrivate::Cmd_DrawPolylineI: {
2000 #ifdef QPAINTBUFFER_DEBUG_DRAW
2001         qDebug() << " -> ExCmd_DrawPolylineI, offset: " << cmd.offset << " size: " << cmd.size;
2002 #endif
2003         xengine->drawPolygon((QPoint *) (d->ints.constData() + cmd.offset), cmd.size, QPaintEngine::PolylineMode);
2004         break; }
2005
2006     case QPaintBufferPrivate::Cmd_DrawRectF: {
2007 #ifdef QPAINTBUFFER_DEBUG_DRAW
2008         qDebug() << " -> ExCmd_DrawRectF, offset: " << cmd.offset << " size: " << cmd.size;
2009 #endif
2010         xengine->drawRects((QRectF *) (d->floats.constData() + cmd.offset), cmd.size);
2011         break; }
2012
2013     case QPaintBufferPrivate::Cmd_DrawRectI: {
2014 #ifdef QPAINTBUFFER_DEBUG_DRAW
2015         qDebug() << " -> ExCmd_DrawRectI, offset: " << cmd.offset << " size: " << cmd.size;
2016 #endif
2017         xengine->drawRects((QRect *) (d->ints.constData() + cmd.offset), cmd.size);
2018         break; }
2019
2020     case QPaintBufferPrivate::Cmd_SetClipEnabled: {
2021         bool clipEnabled = d->variants.at(cmd.offset).toBool();
2022 #ifdef QPAINTBUFFER_DEBUG_DRAW
2023         qDebug() << " -> ExCmd_SetClipEnabled:" << clipEnabled;
2024 #endif
2025         xengine->state()->clipEnabled = clipEnabled;
2026         xengine->clipEnabledChanged();
2027         break; }
2028
2029     case QPaintBufferPrivate::Cmd_ClipVectorPath: {
2030         QVectorPathCmd path(d, cmd);
2031 #ifdef QPAINTBUFFER_DEBUG_DRAW
2032         qDebug() << " -> ExCmd_ClipVectorPath:" << path().elementCount();
2033 #endif
2034         xengine->clip(path(), Qt::ClipOperation(cmd.extra));
2035         break; }
2036
2037
2038     case QPaintBufferPrivate::Cmd_ClipRect: {
2039         QRect rect(QPoint(d->ints.at(cmd.offset), d->ints.at(cmd.offset + 1)),
2040                    QPoint(d->ints.at(cmd.offset + 2), d->ints.at(cmd.offset + 3)));
2041 #ifdef QPAINTBUFFER_DEBUG_DRAW
2042         qDebug() << " -> ExCmd_ClipRect:" << rect << cmd.extra;
2043 #endif
2044         xengine->clip(rect, Qt::ClipOperation(cmd.extra));
2045         break; }
2046
2047     case QPaintBufferPrivate::Cmd_ClipRegion: {
2048         QRegion region(d->variants.at(cmd.offset).value<QRegion>());
2049 #ifdef QPAINTBUFFER_DEBUG_DRAW
2050         qDebug() << " -> ExCmd_ClipRegion:" << region.boundingRect() << cmd.extra;
2051 #endif
2052         xengine->clip(region, Qt::ClipOperation(cmd.extra));
2053         break; }
2054
2055     default:
2056         QPainterReplayer::process(cmd);
2057         break;
2058     }
2059 }
2060
2061 QPaintBufferResource::QPaintBufferResource(FreeFunc f, QObject *parent) : QObject(parent), free(f)
2062 {
2063     connect(QPaintBufferSignalProxy::instance(), SIGNAL(aboutToDestroy(const QPaintBufferPrivate*)), this, SLOT(remove(const QPaintBufferPrivate*)));
2064 }
2065
2066 QPaintBufferResource::~QPaintBufferResource()
2067 {
2068     for (Cache::iterator it = m_cache.begin(); it != m_cache.end(); ++it)
2069         free(it.value());
2070 }
2071
2072 void QPaintBufferResource::insert(const QPaintBufferPrivate *key, void *value)
2073 {
2074     Cache::iterator it = m_cache.find(key);
2075     if (it != m_cache.end()) {
2076         free(it.value());
2077         it.value() = value;
2078     } else {
2079         m_cache.insert(key, value);
2080     }
2081 }
2082
2083 void *QPaintBufferResource::value(const QPaintBufferPrivate *key)
2084 {
2085     Cache::iterator it = m_cache.find(key);
2086     if (it != m_cache.end())
2087         return it.value();
2088     return 0;
2089 }
2090
2091 void QPaintBufferResource::remove(const QPaintBufferPrivate *key)
2092 {
2093     Cache::iterator it = m_cache.find(key);
2094     if (it != m_cache.end()) {
2095         free(it.value());
2096         m_cache.erase(it);
2097     }
2098 }
2099
2100 QDataStream &operator<<(QDataStream &stream, const QPaintBufferCommand &command)
2101 {
2102     quint32 id = command.id;
2103     quint32 size = command.size;
2104     stream << id << size;
2105     stream << command.offset << command.offset2 << command.extra;
2106     return stream;
2107 }
2108
2109 QDataStream &operator>>(QDataStream &stream, QPaintBufferCommand &command)
2110 {
2111     quint32 id;
2112     quint32 size;
2113     stream >> id >> size;
2114     stream >> command.offset >> command.offset2 >> command.extra;
2115     command.id = id;
2116     command.size = size;
2117     return stream;
2118 }
2119
2120 struct QPaintBufferCacheEntry
2121 {
2122     QVariant::Type type;
2123     quint64 cacheKey;
2124 };
2125
2126 struct QPaintBufferCacheEntryV2
2127 {
2128     enum Type {
2129         ImageKey,
2130         PixmapKey
2131     };
2132
2133     struct Flags {
2134         uint type : 8;
2135         uint key : 24;
2136     };
2137
2138     union {
2139         Flags flags;
2140         uint bits;
2141     };
2142 };
2143
2144 QT_END_NAMESPACE
2145 Q_DECLARE_METATYPE(QPaintBufferCacheEntry)
2146 Q_DECLARE_METATYPE(QPaintBufferCacheEntryV2)
2147 QT_BEGIN_NAMESPACE
2148
2149 QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntry &entry)
2150 {
2151     return stream << entry.type << entry.cacheKey;
2152 }
2153
2154 QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntry &entry)
2155 {
2156     return stream >> entry.type >> entry.cacheKey;
2157 }
2158
2159 QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntryV2 &entry)
2160 {
2161     return stream << entry.bits;
2162 }
2163
2164 QDataStream &operator>>(QDataStream &stream, QPaintBufferCacheEntryV2 &entry)
2165 {
2166     return stream >> entry.bits;
2167 }
2168
2169 static int qRegisterPaintBufferMetaTypes()
2170 {
2171     qRegisterMetaType<QPaintBufferCacheEntry>();
2172     qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntry>("QPaintBufferCacheEntry");
2173     qRegisterMetaType<QPaintBufferCacheEntryV2>();
2174     qRegisterMetaTypeStreamOperators<QPaintBufferCacheEntryV2>("QPaintBufferCacheEntryV2");
2175
2176     return 0; // something
2177 }
2178
2179 Q_CONSTRUCTOR_FUNCTION(qRegisterPaintBufferMetaTypes)
2180
2181 QDataStream &operator<<(QDataStream &stream, const QPaintBuffer &buffer)
2182 {
2183     QHash<qint64, uint> pixmapKeys;
2184     QHash<qint64, uint> imageKeys;
2185
2186     QHash<qint64, QPixmap> pixmaps;
2187     QHash<qint64, QImage> images;
2188
2189     QVector<QVariant> variants = buffer.d_ptr->variants;
2190     for (int i = 0; i < variants.size(); ++i) {
2191         const QVariant &v = variants.at(i);
2192         if (v.type() == QVariant::Image) {
2193             const QImage image(v.value<QImage>());
2194
2195             QPaintBufferCacheEntryV2 entry;
2196             entry.flags.type = QPaintBufferCacheEntryV2::ImageKey;
2197
2198             QHash<qint64, uint>::iterator it = imageKeys.find(image.cacheKey());
2199             if (it != imageKeys.end()) {
2200                 entry.flags.key = *it;
2201             } else {
2202                 imageKeys[image.cacheKey()] = entry.flags.key = images.size();
2203                 images[images.size()] = image;
2204             }
2205
2206             variants[i] = QVariant::fromValue(entry);
2207         } else if (v.type() == QVariant::Pixmap) {
2208             const QPixmap pixmap(v.value<QPixmap>());
2209
2210             QPaintBufferCacheEntryV2 entry;
2211             entry.flags.type = QPaintBufferCacheEntryV2::PixmapKey;
2212
2213             QHash<qint64, uint>::iterator it = pixmapKeys.find(pixmap.cacheKey());
2214             if (it != pixmapKeys.end()) {
2215                 entry.flags.key = *it;
2216             } else {
2217                 pixmapKeys[pixmap.cacheKey()] = entry.flags.key = pixmaps.size();
2218                 pixmaps[pixmaps.size()] = pixmap;
2219             }
2220
2221             variants[i] = QVariant::fromValue(entry);
2222         }
2223     }
2224
2225     stream << pixmaps;
2226     stream << images;
2227
2228     stream << buffer.d_ptr->ints;
2229     stream << buffer.d_ptr->floats;
2230     stream << variants;
2231     stream << buffer.d_ptr->commands;
2232     stream << buffer.d_ptr->boundingRect;
2233     stream << buffer.d_ptr->frames;
2234
2235     return stream;
2236 }
2237
2238 QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer)
2239 {
2240     QHash<qint64, QPixmap> pixmaps;
2241     QHash<qint64, QImage> images;
2242
2243     stream >> pixmaps;
2244     stream >> images;
2245
2246     stream >> buffer.d_ptr->ints;
2247     stream >> buffer.d_ptr->floats;
2248     stream >> buffer.d_ptr->variants;
2249     stream >> buffer.d_ptr->commands;
2250     stream >> buffer.d_ptr->boundingRect;
2251     stream >> buffer.d_ptr->frames;
2252
2253     QVector<QVariant> &variants = buffer.d_ptr->variants;
2254     for (int i = 0; i < variants.size(); ++i) {
2255         const QVariant &v = variants.at(i);
2256         if (v.canConvert<QPaintBufferCacheEntry>()) {
2257             QPaintBufferCacheEntry entry = v.value<QPaintBufferCacheEntry>();
2258             if (entry.type == QVariant::Image)
2259                 variants[i] = QVariant(images.value(entry.cacheKey));
2260             else
2261                 variants[i] = QVariant(pixmaps.value(entry.cacheKey));
2262         } else if (v.canConvert<QPaintBufferCacheEntryV2>()) {
2263             QPaintBufferCacheEntryV2 entry = v.value<QPaintBufferCacheEntryV2>();
2264
2265             if (entry.flags.type == QPaintBufferCacheEntryV2::ImageKey)
2266                 variants[i] = QVariant(images.value(entry.flags.key));
2267             else if (entry.flags.type == QPaintBufferCacheEntryV2::PixmapKey)
2268                 variants[i] = QVariant(pixmaps.value(entry.flags.key));
2269             else
2270                 qWarning() << "operator<<(QDataStream &stream, QPaintBuffer &buffer): unrecognized cache entry type:" << entry.flags.type;
2271         }
2272     }
2273
2274     return stream;
2275 }
2276
2277 QT_END_NAMESPACE