Still use midpoint rendering of aliased ellipses
[profile/ivi/qtbase.git] / src / gui / painting / qpaintengine_raster.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
42 #include <QtCore/qglobal.h>
43 #include <QtCore/qmutex.h>
44
45 #define QT_FT_BEGIN_HEADER
46 #define QT_FT_END_HEADER
47
48 #include <private/qrasterdefs_p.h>
49 #include <private/qgrayraster_p.h>
50
51 #include <qpainterpath.h>
52 #include <qdebug.h>
53 #include <qhash.h>
54 #include <qlabel.h>
55 #include <qbitmap.h>
56 #include <qmath.h>
57
58 #if defined (Q_WS_X11)
59 #  include <private/qfontengine_ft_p.h>
60 #endif
61
62 //   #include <private/qdatabuffer_p.h>
63 //   #include <private/qpainter_p.h>
64 #include <private/qmath_p.h>
65 #include <private/qtextengine_p.h>
66 #include <private/qfontengine_p.h>
67 #include <private/qpixmap_raster_p.h>
68 //   #include <private/qpolygonclipper_p.h>
69 //   #include <private/qrasterizer_p.h>
70 #include <private/qimage_p.h>
71 #include <private/qstatictext_p.h>
72 #include <private/qcosmeticstroker_p.h>
73 #include "qmemrotate_p.h"
74
75 #include "qpaintengine_raster_p.h"
76 //   #include "qbezier_p.h"
77 #include "qoutlinemapper_p.h"
78
79 #if defined(Q_WS_WIN)
80 #  include <qt_windows.h>
81 #  include <qvarlengtharray.h>
82 #  include <private/qfontengine_p.h>
83 #  if defined(Q_OS_WINCE)
84 #    include "qguifunctions_wince.h"
85 #  endif
86 #elif defined(Q_WS_MAC)
87 #  include <private/qt_mac_p.h>
88 #  include <private/qpixmap_mac_p.h>
89 #  include <private/qpaintengine_mac_p.h>
90 #elif defined(Q_WS_QWS)
91 #  if !defined(QT_NO_FREETYPE)
92 #    include <private/qfontengine_ft_p.h>
93 #  endif
94 #  if !defined(QT_NO_QWS_QPF2)
95 #    include <private/qfontengine_qpf_p.h>
96 #  endif
97 #  include <private/qabstractfontengine_p.h>
98 #elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
99 #  include <private/qfontengine_s60_p.h>
100 #elif defined(Q_WS_QPA)
101 #  include <private/qfontengine_ft_p.h>
102 #endif
103
104 #if defined(Q_WS_WIN64)
105 #  include <malloc.h>
106 #endif
107 #include <limits.h>
108
109 QT_BEGIN_NAMESPACE
110
111 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
112
113 #define qreal_to_fixed_26_6(f) (int(f * 64))
114 #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
115 #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
116
117 // #define QT_DEBUG_DRAW
118 #ifdef QT_DEBUG_DRAW
119 void dumpClip(int width, int height, const QClipData *clip);
120 #endif
121
122 #define QT_FAST_SPANS
123
124
125 // A little helper macro to get a better approximation of dimensions.
126 // If we have a rect that starting at 0.5 of width 3.5 it should span
127 // 4 pixels.
128 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
129
130 // use the same rounding as in qrasterizer.cpp (6 bit fixed point)
131 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
132
133 #ifdef Q_WS_WIN
134 extern bool qt_cleartype_enabled;
135 #endif
136
137 #ifdef Q_WS_MAC
138 extern bool qt_applefontsmoothing_enabled;
139 #endif
140
141
142 /********************************************************************************
143  * Span functions
144  */
145 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
146 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
147 static void qt_span_clip(int count, const QSpan *spans, void *userData);
148 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
149
150 struct ClipData
151 {
152     QClipData *oldClip;
153     QClipData *newClip;
154     Qt::ClipOperation operation;
155 };
156
157 enum LineDrawMode {
158     LineDrawClipped,
159     LineDrawNormal,
160     LineDrawIncludeLastPixel
161 };
162
163 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
164                                    ProcessSpans pen_func, ProcessSpans brush_func,
165                                    QSpanData *pen_data, QSpanData *brush_data);
166
167 struct QRasterFloatPoint {
168     qreal x;
169     qreal y;
170 };
171
172 #ifdef QT_DEBUG_DRAW
173 static const QRectF boundingRect(const QPointF *points, int pointCount)
174 {
175     const QPointF *e = points;
176     const QPointF *last = points + pointCount;
177     qreal minx, maxx, miny, maxy;
178     minx = maxx = e->x();
179     miny = maxy = e->y();
180     while (++e < last) {
181         if (e->x() < minx)
182             minx = e->x();
183         else if (e->x() > maxx)
184             maxx = e->x();
185         if (e->y() < miny)
186             miny = e->y();
187         else if (e->y() > maxy)
188             maxy = e->y();
189     }
190     return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
191 }
192 #endif
193
194 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
195     return (elementCount == 5 // 5-point polygon, check for closed rect
196             && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
197             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
198             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
199             && pts[0] < pts[4] && pts[1] < pts[5]
200             ) ||
201            (elementCount == 4 // 4-point polygon, check for unclosed rect
202             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
203             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
204             && pts[0] < pts[4] && pts[1] < pts[5]
205             );
206 }
207
208
209 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
210 {
211     ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
212 }
213
214 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
215 {
216     ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
217 }
218
219 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
220                              qfixed c2x, qfixed c2y,
221                              qfixed ex, qfixed ey,
222                              void *data)
223 {
224     ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
225                                        QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
226                                        QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
227 }
228
229
230 #if !defined(QT_NO_DEBUG) && 0
231 static void qt_debug_path(const QPainterPath &path)
232 {
233     const char *names[] = {
234         "MoveTo     ",
235         "LineTo     ",
236         "CurveTo    ",
237         "CurveToData"
238     };
239
240     fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
241     for (int i=0; i<path.elementCount(); ++i) {
242         const QPainterPath::Element &e = path.elementAt(i);
243         Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
244         fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
245     }
246 }
247 #endif
248
249 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
250     QPaintEngineExPrivate(),
251     cachedLines(0)
252 {
253 }
254
255
256 /*!
257     \class QRasterPaintEngine
258     \preliminary
259     \ingroup qws
260     \since 4.2
261
262     \brief The QRasterPaintEngine class enables hardware acceleration
263     of painting operations in Qt for Embedded Linux.
264
265     Note that this functionality is only available in
266     \l{Qt for Embedded Linux}.
267
268     In \l{Qt for Embedded Linux}, painting is a pure software
269     implementation. But starting with Qt 4.2, it is
270     possible to add an accelerated graphics driver to take advantage
271     of available hardware resources.
272
273     Hardware acceleration is accomplished by creating a custom screen
274     driver, accelerating the copying from memory to the screen, and
275     implementing a custom paint engine accelerating the various
276     painting operations. Then a custom paint device (derived from the
277     QCustomRasterPaintDevice class) and a custom window surface
278     (derived from QWSWindowSurface) must be implemented to make
279     \l{Qt for Embedded Linux} aware of the accelerated driver.
280
281     \note The QRasterPaintEngine class does not support 8-bit images.
282     Instead, they need to be converted to a supported format, such as
283     QImage::Format_ARGB32_Premultiplied.
284
285     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
286     documentation for details.
287
288     \sa QCustomRasterPaintDevice, QPaintEngine
289 */
290
291 /*!
292     \fn Type QRasterPaintEngine::type() const
293     \reimp
294 */
295
296 /*!
297     \typedef QSpan
298     \relates QRasterPaintEngine
299
300     A struct equivalent to QT_FT_Span, containing a position (x,
301     y), the span's length in pixels and its color/coverage (a value
302     ranging from 0 to 255).
303 */
304
305 /*!
306     \since 4.5
307
308     Creates a raster based paint engine for operating on the given
309     \a device, with the complete set of \l
310     {QPaintEngine::PaintEngineFeature}{paint engine features and
311     capabilities}.
312 */
313 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
314     : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
315 {
316     d_func()->device = device;
317     init();
318 }
319
320 /*!
321     \internal
322 */
323 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
324     : QPaintEngineEx(dd)
325 {
326     d_func()->device = device;
327     init();
328 }
329
330 void QRasterPaintEngine::init()
331 {
332     Q_D(QRasterPaintEngine);
333
334
335 #ifdef Q_WS_WIN
336     d->hdc = 0;
337 #endif
338
339     // The antialiasing raster.
340     d->grayRaster.reset(new QT_FT_Raster);
341     Q_CHECK_PTR(d->grayRaster.data());
342     if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
343         QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
344
345
346     d->rasterizer.reset(new QRasterizer);
347     d->rasterBuffer.reset(new QRasterBuffer());
348     d->outlineMapper.reset(new QOutlineMapper);
349     d->outlinemapper_xform_dirty = true;
350
351     d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
352     d->basicStroker.setLineToHook(qt_ft_outline_line_to);
353     d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
354
355     d->baseClip.reset(new QClipData(d->device->height()));
356     d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
357
358     d->image_filler.init(d->rasterBuffer.data(), this);
359     d->image_filler.type = QSpanData::Texture;
360
361     d->image_filler_xform.init(d->rasterBuffer.data(), this);
362     d->image_filler_xform.type = QSpanData::Texture;
363
364     d->solid_color_filler.init(d->rasterBuffer.data(), this);
365     d->solid_color_filler.type = QSpanData::Solid;
366
367     d->deviceDepth = d->device->depth();
368
369     d->mono_surface = false;
370     gccaps &= ~PorterDuff;
371
372     QImage::Format format = QImage::Format_Invalid;
373
374     switch (d->device->devType()) {
375     case QInternal::Pixmap:
376         qWarning("QRasterPaintEngine: unsupported for pixmaps...");
377         break;
378     case QInternal::Image:
379         format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
380         break;
381 #ifdef Q_WS_QWS
382     case QInternal::CustomRaster:
383         d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
384         break;
385 #endif
386     default:
387         qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
388         d->device = 0;
389         return;
390     }
391
392     switch (format) {
393     case QImage::Format_MonoLSB:
394     case QImage::Format_Mono:
395         d->mono_surface = true;
396         break;
397     case QImage::Format_ARGB8565_Premultiplied:
398     case QImage::Format_ARGB8555_Premultiplied:
399     case QImage::Format_ARGB6666_Premultiplied:
400     case QImage::Format_ARGB4444_Premultiplied:
401     case QImage::Format_ARGB32_Premultiplied:
402     case QImage::Format_ARGB32:
403         gccaps |= PorterDuff;
404         break;
405     case QImage::Format_RGB32:
406     case QImage::Format_RGB444:
407     case QImage::Format_RGB555:
408     case QImage::Format_RGB666:
409     case QImage::Format_RGB888:
410     case QImage::Format_RGB16:
411         break;
412     default:
413         break;
414     }
415 }
416
417
418
419
420 /*!
421     Destroys this paint engine.
422 */
423 QRasterPaintEngine::~QRasterPaintEngine()
424 {
425     Q_D(QRasterPaintEngine);
426
427     qt_ft_grays_raster.raster_done(*d->grayRaster.data());
428 }
429
430 /*!
431     \reimp
432 */
433 bool QRasterPaintEngine::begin(QPaintDevice *device)
434 {
435     Q_D(QRasterPaintEngine);
436
437     if (device->devType() == QInternal::Pixmap) {
438         QPixmap *pixmap = static_cast<QPixmap *>(device);
439         QPixmapData *pd = pixmap->pixmapData();
440         if (pd->classId() == QPixmapData::RasterClass || pd->classId() == QPixmapData::BlitterClass)
441             d->device = pd->buffer();
442     } else {
443         d->device = device;
444     }
445
446     // Make sure QPaintEngine::paintDevice() returns the proper device.
447     d->pdev = d->device;
448
449     Q_ASSERT(d->device->devType() == QInternal::Image
450              || d->device->devType() == QInternal::CustomRaster);
451
452     d->systemStateChanged();
453
454     QRasterPaintEngineState *s = state();
455     ensureOutlineMapper();
456     d->outlineMapper->m_clip_rect = d->deviceRect;
457
458     if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
459         d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
460     if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
461         d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
462
463     d->rasterizer->setClipRect(d->deviceRect);
464
465     s->penData.init(d->rasterBuffer.data(), this);
466     s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
467     s->stroker = &d->basicStroker;
468     d->basicStroker.setClipRect(d->deviceRect);
469
470     s->brushData.init(d->rasterBuffer.data(), this);
471     s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
472
473     d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
474
475     setDirty(DirtyBrushOrigin);
476
477 #ifdef QT_DEBUG_DRAW
478     qDebug() << "QRasterPaintEngine::begin(" << (void *) device
479              << ") devType:" << device->devType()
480              << "devRect:" << d->deviceRect;
481     if (d->baseClip) {
482         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
483     }
484 #endif
485
486 #if defined(Q_WS_WIN)
487     d->isPlain45DegreeRotation = true;
488 #endif
489
490     if (d->mono_surface)
491         d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
492 #if defined(Q_WS_WIN)
493     else if (qt_cleartype_enabled)
494 #elif defined (Q_WS_MAC)
495     else if (qt_applefontsmoothing_enabled)
496 #else
497     else if (false)
498 #endif
499     {
500         QImage::Format format = static_cast<QImage *>(d->device)->format();
501         if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
502             d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
503         else
504             d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
505     } else
506         d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
507
508     setActive(true);
509     return true;
510 }
511
512 /*!
513     \reimp
514 */
515 bool QRasterPaintEngine::end()
516 {
517 #ifdef QT_DEBUG_DRAW
518     Q_D(QRasterPaintEngine);
519     qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
520     if (d->baseClip) {
521         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
522     }
523 #endif
524
525     return true;
526 }
527
528 /*!
529     \internal
530 */
531 void QRasterPaintEngine::releaseBuffer()
532 {
533     Q_D(QRasterPaintEngine);
534     d->rasterBuffer.reset(new QRasterBuffer);
535 }
536
537 /*!
538     \internal
539 */
540 QSize QRasterPaintEngine::size() const
541 {
542     Q_D(const QRasterPaintEngine);
543     return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
544 }
545
546 /*!
547     \internal
548 */
549 #ifndef QT_NO_DEBUG
550 void QRasterPaintEngine::saveBuffer(const QString &s) const
551 {
552     Q_D(const QRasterPaintEngine);
553     d->rasterBuffer->bufferImage().save(s, "PNG");
554 }
555 #endif
556
557 /*!
558     \internal
559 */
560 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
561 {
562     QRasterPaintEngineState *s = state();
563     // FALCON: get rid of this line, see drawImage call below.
564     s->matrix = matrix;
565     QTransform::TransformationType txop = s->matrix.type();
566
567     switch (txop) {
568
569     case QTransform::TxNone:
570         s->flags.int_xform = true;
571         break;
572
573     case QTransform::TxTranslate:
574         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
575                             && qreal(int(s->matrix.dy())) == s->matrix.dy();
576         break;
577
578     case QTransform::TxScale:
579         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
580                             && qreal(int(s->matrix.dy())) == s->matrix.dy()
581                             && qreal(int(s->matrix.m11())) == s->matrix.m11()
582                             && qreal(int(s->matrix.m22())) == s->matrix.m22();
583         break;
584
585     default: // shear / perspective...
586         s->flags.int_xform = false;
587         break;
588     }
589
590     s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
591
592     ensureOutlineMapper();
593
594 #ifdef Q_WS_WIN
595     Q_D(QRasterPaintEngine);
596     d->isPlain45DegreeRotation = false;
597     if (txop >= QTransform::TxRotate) {
598         d->isPlain45DegreeRotation =
599             (qFuzzyIsNull(matrix.m11())
600              && qFuzzyIsNull(matrix.m12() - qreal(1))
601              && qFuzzyIsNull(matrix.m21() + qreal(1))
602              && qFuzzyIsNull(matrix.m22())
603                 )
604             ||
605             (qFuzzyIsNull(matrix.m11() + qreal(1))
606              && qFuzzyIsNull(matrix.m12())
607              && qFuzzyIsNull(matrix.m21())
608              && qFuzzyIsNull(matrix.m22() + qreal(1))
609                 )
610             ||
611             (qFuzzyIsNull(matrix.m11())
612              && qFuzzyIsNull(matrix.m12() + qreal(1))
613              && qFuzzyIsNull(matrix.m21() - qreal(1))
614              && qFuzzyIsNull(matrix.m22())
615                 )
616             ;
617     }
618 #endif
619
620 }
621
622
623
624 QRasterPaintEngineState::~QRasterPaintEngineState()
625 {
626     if (flags.has_clip_ownership)
627         delete clip;
628 }
629
630
631 QRasterPaintEngineState::QRasterPaintEngineState()
632 {
633     stroker = 0;
634
635     fillFlags = 0;
636     strokeFlags = 0;
637     pixmapFlags = 0;
638
639     intOpacity = 256;
640
641     txscale = 1.;
642
643     flags.fast_pen = true;
644     flags.antialiased = false;
645     flags.bilinear = false;
646     flags.fast_text = true;
647     flags.int_xform = true;
648     flags.tx_noshear = true;
649     flags.fast_images = true;
650
651     clip = 0;
652     flags.has_clip_ownership = false;
653
654     dirty = 0;
655 }
656
657 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
658     : QPainterState(s)
659     , lastPen(s.lastPen)
660     , penData(s.penData)
661     , stroker(s.stroker)
662     , strokeFlags(s.strokeFlags)
663     , lastBrush(s.lastBrush)
664     , brushData(s.brushData)
665     , fillFlags(s.fillFlags)
666     , pixmapFlags(s.pixmapFlags)
667     , intOpacity(s.intOpacity)
668     , txscale(s.txscale)
669     , clip(s.clip)
670     , dirty(s.dirty)
671     , flag_bits(s.flag_bits)
672 {
673     brushData.tempImage = 0;
674     penData.tempImage = 0;
675     flags.has_clip_ownership = false;
676 }
677
678 /*!
679     \internal
680 */
681 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
682 {
683     QRasterPaintEngineState *s;
684     if (!orig)
685         s = new QRasterPaintEngineState();
686     else
687         s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
688
689     return s;
690 }
691
692 /*!
693     \internal
694 */
695 void QRasterPaintEngine::setState(QPainterState *s)
696 {
697     Q_D(QRasterPaintEngine);
698     QPaintEngineEx::setState(s);
699     d->rasterBuffer->compositionMode = s->composition_mode;
700 }
701
702 /*!
703     \fn QRasterPaintEngineState *QRasterPaintEngine::state()
704     \internal
705 */
706
707 /*!
708     \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
709     \internal
710 */
711
712 /*!
713     \internal
714 */
715 void QRasterPaintEngine::penChanged()
716 {
717 #ifdef QT_DEBUG_DRAW
718     qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
719 #endif
720     QRasterPaintEngineState *s = state();
721     s->strokeFlags |= DirtyPen;
722     s->dirty |= DirtyPen;
723 }
724
725 /*!
726     \internal
727 */
728 void QRasterPaintEngine::updatePen(const QPen &pen)
729 {
730     Q_D(QRasterPaintEngine);
731     QRasterPaintEngineState *s = state();
732 #ifdef QT_DEBUG_DRAW
733     qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
734 #endif
735
736     Qt::PenStyle pen_style = qpen_style(pen);
737
738     s->lastPen = pen;
739     s->strokeFlags = 0;
740
741     s->penData.clip = d->clip();
742     s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
743
744     if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
745         || pen.brush().transform().type() >= QTransform::TxNone) {
746         d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
747     }
748
749     // Slightly ugly handling of an uncommon case... We need to change
750     // the pen because it is reused in draw_midpoint to decide dashed
751     // or non-dashed.
752     if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
753         pen_style = Qt::SolidLine;
754         s->lastPen.setStyle(Qt::SolidLine);
755     }
756
757     d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
758     d->basicStroker.setCapStyle(qpen_capStyle(pen));
759     d->basicStroker.setMiterLimit(pen.miterLimit());
760
761     qreal penWidth = qpen_widthf(pen);
762     if (penWidth == 0)
763         d->basicStroker.setStrokeWidth(1);
764     else
765         d->basicStroker.setStrokeWidth(penWidth);
766
767     if(pen_style == Qt::SolidLine) {
768         s->stroker = &d->basicStroker;
769     } else if (pen_style != Qt::NoPen) {
770         if (!d->dashStroker)
771             d->dashStroker.reset(new QDashStroker(&d->basicStroker));
772         if (pen.isCosmetic()) {
773             d->dashStroker->setClipRect(d->deviceRect);
774         } else {
775             // ### I've seen this inverted devrect multiple places now...
776             QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
777             d->dashStroker->setClipRect(clipRect);
778         }
779         d->dashStroker->setDashPattern(pen.dashPattern());
780         d->dashStroker->setDashOffset(pen.dashOffset());
781         s->stroker = d->dashStroker.data();
782     } else {
783         s->stroker = 0;
784     }
785
786     ensureState(); // needed because of tx_noshear...
787     s->flags.fast_pen = pen_style > Qt::NoPen
788             && s->penData.blend
789             && ((pen.isCosmetic() && penWidth <= 1)
790                 || (s->flags.tx_noshear && penWidth * s->txscale <= 1));
791
792     s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
793
794     s->strokeFlags = 0;
795 }
796
797
798
799 /*!
800     \internal
801 */
802 void QRasterPaintEngine::brushOriginChanged()
803 {
804     QRasterPaintEngineState *s = state();
805 #ifdef QT_DEBUG_DRAW
806     qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
807 #endif
808
809     s->fillFlags |= DirtyBrushOrigin;
810 }
811
812
813 /*!
814     \internal
815 */
816 void QRasterPaintEngine::brushChanged()
817 {
818     QRasterPaintEngineState *s = state();
819 #ifdef QT_DEBUG_DRAW
820     qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
821 #endif
822     s->fillFlags |= DirtyBrush;
823 }
824
825
826
827
828 /*!
829     \internal
830 */
831 void QRasterPaintEngine::updateBrush(const QBrush &brush)
832 {
833 #ifdef QT_DEBUG_DRAW
834     qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
835 #endif
836     Q_D(QRasterPaintEngine);
837     QRasterPaintEngineState *s = state();
838     // must set clip prior to setup, as setup uses it...
839     s->brushData.clip = d->clip();
840     s->brushData.setup(brush, s->intOpacity, s->composition_mode);
841     if (s->fillFlags & DirtyTransform
842         || brush.transform().type() >= QTransform::TxNone)
843         d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
844     s->lastBrush = brush;
845     s->fillFlags = 0;
846 }
847
848 void QRasterPaintEngine::updateOutlineMapper()
849 {
850     Q_D(QRasterPaintEngine);
851     d->outlineMapper->setMatrix(state()->matrix);
852 }
853
854 void QRasterPaintEngine::updateState()
855 {
856     QRasterPaintEngineState *s = state();
857
858     if (s->dirty & DirtyTransform)
859         updateMatrix(s->matrix);
860
861     if (s->dirty & (DirtyPen|DirtyCompositionMode|DirtyOpacity)) {
862         const QPainter::CompositionMode mode = s->composition_mode;
863         s->flags.fast_text = (s->penData.type == QSpanData::Solid)
864                        && s->intOpacity == 256
865                        && (mode == QPainter::CompositionMode_Source
866                            || (mode == QPainter::CompositionMode_SourceOver
867                                && qAlpha(s->penData.solid.color) == 255));
868     }
869
870     s->dirty = 0;
871 }
872
873
874 /*!
875     \internal
876 */
877 void QRasterPaintEngine::opacityChanged()
878 {
879     QRasterPaintEngineState *s = state();
880
881 #ifdef QT_DEBUG_DRAW
882     qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
883 #endif
884
885     s->fillFlags |= DirtyOpacity;
886     s->strokeFlags |= DirtyOpacity;
887     s->pixmapFlags |= DirtyOpacity;
888     s->dirty |= DirtyOpacity;
889     s->intOpacity = (int) (s->opacity * 256);
890 }
891
892 /*!
893     \internal
894 */
895 void QRasterPaintEngine::compositionModeChanged()
896 {
897     Q_D(QRasterPaintEngine);
898     QRasterPaintEngineState *s = state();
899
900 #ifdef QT_DEBUG_DRAW
901     qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
902 #endif
903
904     s->fillFlags |= DirtyCompositionMode;
905     s->dirty |= DirtyCompositionMode;
906
907     s->strokeFlags |= DirtyCompositionMode;
908     d->rasterBuffer->compositionMode = s->composition_mode;
909
910     d->recalculateFastImages();
911 }
912
913 /*!
914     \internal
915 */
916 void QRasterPaintEngine::renderHintsChanged()
917 {
918     QRasterPaintEngineState *s = state();
919
920 #ifdef QT_DEBUG_DRAW
921     qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
922 #endif
923
924     bool was_aa = s->flags.antialiased;
925     bool was_bilinear = s->flags.bilinear;
926
927     s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
928     s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
929
930     if (was_aa != s->flags.antialiased)
931         s->strokeFlags |= DirtyHints;
932
933     if (was_bilinear != s->flags.bilinear) {
934         s->strokeFlags |= DirtyPen;
935         s->fillFlags |= DirtyBrush;
936     }
937
938     Q_D(QRasterPaintEngine);
939     d->recalculateFastImages();
940 }
941
942 /*!
943     \internal
944 */
945 void QRasterPaintEngine::transformChanged()
946 {
947     QRasterPaintEngineState *s = state();
948
949 #ifdef QT_DEBUG_DRAW
950     qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
951 #endif
952
953     s->fillFlags |= DirtyTransform;
954     s->strokeFlags |= DirtyTransform;
955
956     s->dirty |= DirtyTransform;
957
958     Q_D(QRasterPaintEngine);
959     d->recalculateFastImages();
960 }
961
962 /*!
963     \internal
964 */
965 void QRasterPaintEngine::clipEnabledChanged()
966 {
967     QRasterPaintEngineState *s = state();
968
969 #ifdef QT_DEBUG_DRAW
970     qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
971 #endif
972
973     if (s->clip) {
974         s->clip->enabled = s->clipEnabled;
975         s->fillFlags |= DirtyClipEnabled;
976         s->strokeFlags |= DirtyClipEnabled;
977         s->pixmapFlags |= DirtyClipEnabled;
978     }
979 }
980
981 #ifdef Q_WS_QWS
982 void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
983 {
984     rasterBuffer->prepare(device);
985 }
986 #endif
987
988 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
989                                           const QImage &img,
990                                           SrcOverBlendFunc func,
991                                           const QRect &clip,
992                                           int alpha,
993                                           const QRect &sr)
994 {
995     if (alpha == 0 || !clip.isValid())
996         return;
997
998     Q_ASSERT(img.depth() >= 8);
999
1000     int srcBPL = img.bytesPerLine();
1001     const uchar *srcBits = img.bits();
1002     int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
1003     int iw = img.width();
1004     int ih = img.height();
1005
1006     if (!sr.isEmpty()) {
1007         iw = sr.width();
1008         ih = sr.height();
1009         // Adjust the image according to the source offset...
1010         srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1011     }
1012
1013     // adapt the x parameters
1014     int x = qRound(pt.x());
1015     int cx1 = clip.x();
1016     int cx2 = clip.x() + clip.width();
1017     if (x < cx1) {
1018         int d = cx1 - x;
1019         srcBits += srcSize * d;
1020         iw -= d;
1021         x = cx1;
1022     }
1023     if (x + iw > cx2) {
1024         int d = x + iw - cx2;
1025         iw -= d;
1026     }
1027     if (iw <= 0)
1028         return;
1029
1030     // adapt the y paremeters...
1031     int cy1 = clip.y();
1032     int cy2 = clip.y() + clip.height();
1033     int y = qRound(pt.y());
1034     if (y < cy1) {
1035         int d = cy1 - y;
1036         srcBits += srcBPL * d;
1037         ih -= d;
1038         y = cy1;
1039     }
1040     if (y + ih > cy2) {
1041         int d = y + ih - cy2;
1042         ih -= d;
1043     }
1044     if (ih <= 0)
1045         return;
1046
1047     // call the blend function...
1048     int dstSize = rasterBuffer->bytesPerPixel();
1049     int dstBPL = rasterBuffer->bytesPerLine();
1050     func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1051          srcBits, srcBPL,
1052          iw, ih,
1053          alpha);
1054 }
1055
1056
1057 void QRasterPaintEnginePrivate::systemStateChanged()
1058 {
1059     QRect clipRect(0, 0,
1060             qMin(QT_RASTER_COORD_LIMIT, device->width()),
1061             qMin(QT_RASTER_COORD_LIMIT, device->height()));
1062
1063     if (!systemClip.isEmpty()) {
1064         QRegion clippedDeviceRgn = systemClip & clipRect;
1065         deviceRect = clippedDeviceRgn.boundingRect();
1066         baseClip->setClipRegion(clippedDeviceRgn);
1067     } else {
1068         deviceRect = clipRect;
1069         baseClip->setClipRect(deviceRect);
1070     }
1071 #ifdef QT_DEBUG_DRAW
1072     qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
1073 #endif
1074
1075     exDeviceRect = deviceRect;
1076
1077     Q_Q(QRasterPaintEngine);
1078     q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1079     q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1080     q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1081 }
1082
1083 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1084 {
1085     if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1086         return;
1087
1088     Q_Q(QRasterPaintEngine);
1089     bool bilinear = q->state()->flags.bilinear;
1090
1091     if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1092         spanData->setupMatrix(b.transform() * m, bilinear);
1093     } else {
1094         if (m.type() <= QTransform::TxTranslate) {
1095             // specialize setupMatrix for translation matrices
1096             // to avoid needless matrix inversion
1097             spanData->m11 = 1;
1098             spanData->m12 = 0;
1099             spanData->m13 = 0;
1100             spanData->m21 = 0;
1101             spanData->m22 = 1;
1102             spanData->m23 = 0;
1103             spanData->m33 = 1;
1104             spanData->dx = -m.dx();
1105             spanData->dy = -m.dy();
1106             spanData->txop = m.type();
1107             spanData->bilinear = bilinear;
1108             spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1109             spanData->adjustSpanMethods();
1110         } else {
1111             spanData->setupMatrix(m, bilinear);
1112         }
1113     }
1114 }
1115
1116 // #define QT_CLIPPING_RATIOS
1117
1118 #ifdef QT_CLIPPING_RATIOS
1119 int rectClips;
1120 int regionClips;
1121 int totalClips;
1122
1123 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1124 {
1125     if (d->clip()->hasRectClip)
1126         rectClips++;
1127     if (d->clip()->hasRegionClip)
1128         regionClips++;
1129     totalClips++;
1130
1131     if ((totalClips % 5000) == 0) {
1132         printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1133                rectClips * 100.0 / (qreal) totalClips,
1134                regionClips * 100.0 / (qreal) totalClips,
1135                (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1136         totalClips = 0;
1137         rectClips = 0;
1138         regionClips = 0;
1139     }
1140
1141 }
1142 #endif
1143
1144 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1145 {
1146     if (s->flags.has_clip_ownership)
1147         delete s->clip;
1148     s->clip = 0;
1149     s->flags.has_clip_ownership = false;
1150 }
1151
1152 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1153 {
1154     s->fillFlags |= QPaintEngine::DirtyClipPath;
1155     s->strokeFlags |= QPaintEngine::DirtyClipPath;
1156     s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1157
1158     d->solid_color_filler.clip = d->clip();
1159     d->solid_color_filler.adjustSpanMethods();
1160
1161 #ifdef QT_DEBUG_DRAW
1162     dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1163 #endif
1164
1165 }
1166
1167
1168 /*!
1169     \internal
1170 */
1171 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1172 {
1173 #ifdef QT_DEBUG_DRAW
1174     qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1175
1176     if (path.elements()) {
1177         for (int i=0; i<path.elementCount(); ++i) {
1178             qDebug() << " - " << path.elements()[i]
1179                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1180         }
1181     } else {
1182         for (int i=0; i<path.elementCount(); ++i) {
1183             qDebug() << " ---- "
1184                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1185         }
1186     }
1187 #endif
1188
1189     Q_D(QRasterPaintEngine);
1190     QRasterPaintEngineState *s = state();
1191
1192     const qreal *points = path.points();
1193     const QPainterPath::ElementType *types = path.elements();
1194
1195     // There are some cases that are not supported by clip(QRect)
1196     if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
1197                                 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
1198         if (s->matrix.type() <= QTransform::TxScale
1199             && ((path.shape() == QVectorPath::RectangleHint)
1200                 || (isRect(points, path.elementCount())
1201                     && (!types || (types[0] == QPainterPath::MoveToElement
1202                                    && types[1] == QPainterPath::LineToElement
1203                                    && types[2] == QPainterPath::LineToElement
1204                                    && types[3] == QPainterPath::LineToElement))))) {
1205 #ifdef QT_DEBUG_DRAW
1206             qDebug() << " --- optimizing vector clip to rect clip...";
1207 #endif
1208
1209             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1210             if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1211                 return;
1212         }
1213     }
1214
1215     if (op == Qt::NoClip) {
1216         qrasterpaintengine_state_setNoClip(s);
1217
1218     } else {
1219         QClipData *base = d->baseClip.data();
1220
1221         // Intersect with current clip when available...
1222         if (op == Qt::IntersectClip && s->clip)
1223             base = s->clip;
1224
1225         // We always intersect, except when there is nothing to
1226         // intersect with, in which case we simplify the operation to
1227         // a replace...
1228         Qt::ClipOperation isectOp = Qt::IntersectClip;
1229         if (base == 0)
1230             isectOp = Qt::ReplaceClip;
1231
1232         QClipData *newClip = new QClipData(d->rasterBuffer->height());
1233         newClip->initialize();
1234         ClipData clipData = { base, newClip, isectOp };
1235         ensureOutlineMapper();
1236         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1237
1238         newClip->fixup();
1239
1240         if (op == Qt::UniteClip) {
1241             // merge clips
1242             QClipData *result = new QClipData(d->rasterBuffer->height());
1243             QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
1244             qt_merge_clip(current, newClip, result);
1245             result->fixup();
1246             delete newClip;
1247             if (!s->clip)
1248                 delete current;
1249             newClip = result;
1250         }
1251
1252         if (s->flags.has_clip_ownership)
1253             delete s->clip;
1254
1255         s->clip = newClip;
1256         s->flags.has_clip_ownership = true;
1257     }
1258     qrasterpaintengine_dirty_clip(d, s);
1259 }
1260
1261
1262
1263 /*!
1264     \internal
1265 */
1266 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1267 {
1268 #ifdef QT_DEBUG_DRAW
1269     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1270 #endif
1271
1272     QRasterPaintEngineState *s = state();
1273
1274     if (op == Qt::NoClip) {
1275         qrasterpaintengine_state_setNoClip(s);
1276
1277     } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1278         QPaintEngineEx::clip(rect, op);
1279         return;
1280
1281     } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1282         QPaintEngineEx::clip(rect, op);
1283         return;
1284     }
1285 }
1286
1287
1288 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1289 {
1290     Q_D(QRasterPaintEngine);
1291     QRect clipRect = r & d->deviceRect;
1292     QRasterPaintEngineState *s = state();
1293
1294     if (op == Qt::ReplaceClip || s->clip == 0) {
1295
1296         // No current clip, hence we intersect with sysclip and be
1297         // done with it...
1298         QRegion clipRegion = systemClip();
1299         QClipData *clip = new QClipData(d->rasterBuffer->height());
1300
1301         if (clipRegion.isEmpty())
1302             clip->setClipRect(clipRect);
1303         else
1304             clip->setClipRegion(clipRegion & clipRect);
1305
1306         if (s->flags.has_clip_ownership)
1307             delete s->clip;
1308
1309         s->clip = clip;
1310         s->clip->enabled = true;
1311         s->flags.has_clip_ownership = true;
1312
1313     } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1314         QClipData *base = s->clip;
1315
1316         Q_ASSERT(base);
1317         if (base->hasRectClip || base->hasRegionClip) {
1318             if (!s->flags.has_clip_ownership) {
1319                 s->clip = new QClipData(d->rasterBuffer->height());
1320                 s->flags.has_clip_ownership = true;
1321             }
1322             if (base->hasRectClip)
1323                 s->clip->setClipRect(base->clipRect & clipRect);
1324             else
1325                 s->clip->setClipRegion(base->clipRegion & clipRect);
1326             s->clip->enabled = true;
1327         } else {
1328             return false;
1329         }
1330     } else {
1331         return false;
1332     }
1333
1334     qrasterpaintengine_dirty_clip(d, s);
1335     return true;
1336 }
1337
1338
1339 /*!
1340     \internal
1341 */
1342 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1343 {
1344 #ifdef QT_DEBUG_DRAW
1345     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1346 #endif
1347
1348     Q_D(QRasterPaintEngine);
1349
1350     if (region.rectCount() == 1) {
1351         clip(region.boundingRect(), op);
1352         return;
1353     }
1354
1355     QRasterPaintEngineState *s = state();
1356     const QClipData *clip = d->clip();
1357     const QClipData *baseClip = d->baseClip.data();
1358
1359     if (op == Qt::NoClip) {
1360         qrasterpaintengine_state_setNoClip(s);
1361     } else if (s->matrix.type() > QTransform::TxScale
1362                || op == Qt::UniteClip
1363                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1364                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1365         QPaintEngineEx::clip(region, op);
1366     } else {
1367         const QClipData *curClip;
1368         QClipData *newClip;
1369
1370         if (op == Qt::IntersectClip)
1371             curClip = clip;
1372         else
1373             curClip = baseClip;
1374
1375         if (s->flags.has_clip_ownership) {
1376             newClip = s->clip;
1377             Q_ASSERT(newClip);
1378         } else {
1379             newClip = new QClipData(d->rasterBuffer->height());
1380             s->clip = newClip;
1381             s->flags.has_clip_ownership = true;
1382         }
1383
1384         QRegion r = s->matrix.map(region);
1385         if (curClip->hasRectClip)
1386             newClip->setClipRegion(r & curClip->clipRect);
1387         else if (curClip->hasRegionClip)
1388             newClip->setClipRegion(r & curClip->clipRegion);
1389
1390         qrasterpaintengine_dirty_clip(d, s);
1391     }
1392 }
1393
1394 /*!
1395     \internal
1396 */
1397 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1398 {
1399 #ifdef QT_DEBUG_DRAW
1400     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1401 #endif
1402
1403     if (!fillData->blend)
1404         return;
1405
1406     Q_D(QRasterPaintEngine);
1407
1408     const QRectF controlPointRect = path.controlPointRect();
1409
1410     QRasterPaintEngineState *s = state();
1411     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1412     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1413     const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1414                           || deviceRect.right() > QT_RASTER_COORD_LIMIT
1415                           || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1416                           || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1417
1418     if (!s->flags.antialiased && !do_clip) {
1419         d->initializeRasterizer(fillData);
1420         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1421         return;
1422     }
1423
1424     ensureOutlineMapper();
1425     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1426 }
1427
1428 static void fillRect_normalized(const QRect &r, QSpanData *data,
1429                                 QRasterPaintEnginePrivate *pe)
1430 {
1431     int x1, x2, y1, y2;
1432
1433     bool rectClipped = true;
1434
1435     if (data->clip) {
1436         x1 = qMax(r.x(), data->clip->xmin);
1437         x2 = qMin(r.x() + r.width(), data->clip->xmax);
1438         y1 = qMax(r.y(), data->clip->ymin);
1439         y2 = qMin(r.y() + r.height(), data->clip->ymax);
1440         rectClipped = data->clip->hasRectClip;
1441
1442     } else if (pe) {
1443         x1 = qMax(r.x(), pe->deviceRect.x());
1444         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1445         y1 = qMax(r.y(), pe->deviceRect.y());
1446         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1447     } else {
1448         x1 = qMax(r.x(), 0);
1449         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1450         y1 = qMax(r.y(), 0);
1451         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1452     }
1453
1454     if (x2 <= x1 || y2 <= y1)
1455         return;
1456
1457     const int width = x2 - x1;
1458     const int height = y2 - y1;
1459
1460     bool isUnclipped = rectClipped
1461                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1462
1463     if (pe && isUnclipped) {
1464         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1465
1466         if (data->fillRect && (mode == QPainter::CompositionMode_Source
1467                                || (mode == QPainter::CompositionMode_SourceOver
1468                                    && qAlpha(data->solid.color) == 255)))
1469         {
1470             data->fillRect(data->rasterBuffer, x1, y1, width, height,
1471                            data->solid.color);
1472             return;
1473         }
1474     }
1475
1476     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1477
1478     const int nspans = 256;
1479     QT_FT_Span spans[nspans];
1480
1481     Q_ASSERT(data->blend);
1482     int y = y1;
1483     while (y < y2) {
1484         int n = qMin(nspans, y2 - y);
1485         int i = 0;
1486         while (i < n) {
1487             spans[i].x = x1;
1488             spans[i].len = width;
1489             spans[i].y = y + i;
1490             spans[i].coverage = 255;
1491             ++i;
1492         }
1493
1494         blend(n, spans, data);
1495         y += n;
1496     }
1497 }
1498
1499 /*!
1500     \reimp
1501 */
1502 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1503 {
1504 #ifdef QT_DEBUG_DRAW
1505     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1506 #endif
1507     Q_D(QRasterPaintEngine);
1508     ensureState();
1509     QRasterPaintEngineState *s = state();
1510
1511     // Fill
1512     ensureBrush();
1513     if (s->brushData.blend) {
1514         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1515             const QRect *r = rects;
1516             const QRect *lastRect = rects + rectCount;
1517
1518             int offset_x = int(s->matrix.dx());
1519             int offset_y = int(s->matrix.dy());
1520             while (r < lastRect) {
1521                 QRect rect = r->normalized();
1522                 QRect rr = rect.translated(offset_x, offset_y);
1523                 fillRect_normalized(rr, &s->brushData, d);
1524                 ++r;
1525             }
1526         } else {
1527             QRectVectorPath path;
1528             for (int i=0; i<rectCount; ++i) {
1529                 path.set(rects[i]);
1530                 fill(path, s->brush);
1531             }
1532         }
1533     }
1534
1535     ensurePen();
1536     if (s->penData.blend) {
1537         QRectVectorPath path;
1538         if (s->flags.fast_pen) {
1539             QCosmeticStroker stroker(s, d->deviceRect);
1540             for (int i = 0; i < rectCount; ++i) {
1541                 path.set(rects[i]);
1542                 stroker.drawPath(path);
1543             }
1544         } else {
1545             for (int i = 0; i < rectCount; ++i) {
1546                 path.set(rects[i]);
1547                 stroke(path, s->pen);
1548             }
1549         }
1550     }
1551 }
1552
1553 /*!
1554     \reimp
1555 */
1556 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1557 {
1558 #ifdef QT_DEBUG_DRAW
1559     qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1560 #endif
1561 #ifdef QT_FAST_SPANS
1562     Q_D(QRasterPaintEngine);
1563     ensureState();
1564     QRasterPaintEngineState *s = state();
1565
1566
1567     if (s->flags.tx_noshear) {
1568         ensureBrush();
1569         if (s->brushData.blend) {
1570             d->initializeRasterizer(&s->brushData);
1571             for (int i = 0; i < rectCount; ++i) {
1572                 const QRectF &rect = rects[i].normalized();
1573                 if (rect.isEmpty())
1574                     continue;
1575                 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1576                 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1577                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1578             }
1579         }
1580
1581         ensurePen();
1582         if (s->penData.blend) {
1583             QRectVectorPath path;
1584             if (s->flags.fast_pen) {
1585                 QCosmeticStroker stroker(s, d->deviceRect);
1586                 for (int i = 0; i < rectCount; ++i) {
1587                     path.set(rects[i]);
1588                     stroker.drawPath(path);
1589                 }
1590             } else {
1591                 for (int i = 0; i < rectCount; ++i) {
1592                     path.set(rects[i]);
1593                     QPaintEngineEx::stroke(path, s->lastPen);
1594                 }
1595             }
1596         }
1597
1598         return;
1599     }
1600 #endif // QT_FAST_SPANS
1601     QPaintEngineEx::drawRects(rects, rectCount);
1602 }
1603
1604
1605 /*!
1606     \internal
1607 */
1608 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1609 {
1610     Q_D(QRasterPaintEngine);
1611     QRasterPaintEngineState *s = state();
1612
1613     ensurePen(pen);
1614     if (!s->penData.blend)
1615         return;
1616
1617     if (s->flags.fast_pen) {
1618         QCosmeticStroker stroker(s, d->deviceRect);
1619         stroker.drawPath(path);
1620     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1621         qreal width = s->lastPen.isCosmetic()
1622                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1623                       : qpen_widthf(s->lastPen) * s->txscale;
1624         int dashIndex = 0;
1625         qreal dashOffset = s->lastPen.dashOffset();
1626         bool inDash = true;
1627         qreal patternLength = 0;
1628         const QVector<qreal> pattern = s->lastPen.dashPattern();
1629         for (int i = 0; i < pattern.size(); ++i)
1630             patternLength += pattern.at(i);
1631
1632         if (patternLength > 0) {
1633             int n = qFloor(dashOffset / patternLength);
1634             dashOffset -= n * patternLength;
1635             while (dashOffset >= pattern.at(dashIndex)) {
1636                 dashOffset -= pattern.at(dashIndex);
1637                 if (++dashIndex >= pattern.size())
1638                     dashIndex = 0;
1639                 inDash = !inDash;
1640             }
1641         }
1642
1643         Q_D(QRasterPaintEngine);
1644         d->initializeRasterizer(&s->penData);
1645         int lineCount = path.elementCount() / 2;
1646         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1647
1648         for (int i = 0; i < lineCount; ++i) {
1649             if (lines[i].p1() == lines[i].p2()) {
1650                 if (s->lastPen.capStyle() != Qt::FlatCap) {
1651                     QPointF p = lines[i].p1();
1652                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1653                                                        QPointF(p.x() + width*0.5, p.y())));
1654                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1655                 }
1656                 continue;
1657             }
1658
1659             const QLineF line = s->matrix.map(lines[i]);
1660             if (qpen_style(s->lastPen) == Qt::SolidLine) {
1661                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1662                                             width / line.length(),
1663                                             s->lastPen.capStyle() == Qt::SquareCap);
1664             } else {
1665                 d->rasterizeLine_dashed(line, width,
1666                                         &dashIndex, &dashOffset, &inDash);
1667             }
1668         }
1669     }
1670     else
1671         QPaintEngineEx::stroke(path, pen);
1672 }
1673
1674 static inline QRect toNormalizedFillRect(const QRectF &rect)
1675 {
1676     int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1677     int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1678     int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1679     int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1680
1681     if (x2 < x1)
1682         qSwap(x1, x2);
1683     if (y2 < y1)
1684         qSwap(y1, y2);
1685
1686     return QRect(x1, y1, x2 - x1, y2 - y1);
1687 }
1688
1689 /*!
1690     \internal
1691 */
1692 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1693 {
1694     if (path.isEmpty())
1695         return;
1696 #ifdef QT_DEBUG_DRAW
1697     QRectF rf = path.controlPointRect();
1698     qDebug() << "QRasterPaintEngine::fill(): "
1699              << "size=" << path.elementCount()
1700              << ", hints=" << hex << path.hints()
1701              << rf << brush;
1702 #endif
1703
1704     Q_D(QRasterPaintEngine);
1705     QRasterPaintEngineState *s = state();
1706
1707     ensureBrush(brush);
1708     if (!s->brushData.blend)
1709         return;
1710
1711     if (path.shape() == QVectorPath::RectangleHint) {
1712         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1713             const qreal *p = path.points();
1714             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1715             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1716             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1717             return;
1718         }
1719         ensureState();
1720         if (s->flags.tx_noshear) {
1721             d->initializeRasterizer(&s->brushData);
1722             // ### Is normalizing really necessary here?
1723             const qreal *p = path.points();
1724             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1725             if (!r.isEmpty()) {
1726                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1727                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1728                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1729             }
1730             return;
1731         }
1732     }
1733
1734     // ### Optimize for non transformed ellipses and rectangles...
1735     QRectF cpRect = path.controlPointRect();
1736     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1737     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1738
1739         // ### Falcon
1740 //         const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1741 //                               || deviceRect.right() > QT_RASTER_COORD_LIMIT
1742 //                               || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1743 //                               || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1744
1745         // ### Falonc: implement....
1746 //         if (!s->flags.antialiased && !do_clip) {
1747 //             d->initializeRasterizer(&s->brushData);
1748 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1749 //             return;
1750 //         }
1751
1752     ensureOutlineMapper();
1753     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1754 }
1755
1756 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1757 {
1758     Q_D(QRasterPaintEngine);
1759     QRasterPaintEngineState *s = state();
1760
1761     if (!s->flags.antialiased) {
1762         uint txop = s->matrix.type();
1763         if (txop == QTransform::TxNone) {
1764             fillRect_normalized(toNormalizedFillRect(r), data, d);
1765             return;
1766         } else if (txop == QTransform::TxTranslate) {
1767             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1768             fillRect_normalized(rr, data, d);
1769             return;
1770         } else if (txop == QTransform::TxScale) {
1771             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1772             fillRect_normalized(rr, data, d);
1773             return;
1774         }
1775     }
1776     ensureState();
1777     if (s->flags.tx_noshear) {
1778         d->initializeRasterizer(data);
1779         QRectF nr = r.normalized();
1780         if (!nr.isEmpty()) {
1781             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1782             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1783             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1784         }
1785         return;
1786     }
1787
1788     QPainterPath path;
1789     path.addRect(r);
1790     ensureOutlineMapper();
1791     fillPath(path, data);
1792 }
1793
1794 /*!
1795     \reimp
1796 */
1797 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1798 {
1799 #ifdef QT_DEBUG_DRAW
1800     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1801 #endif
1802     QRasterPaintEngineState *s = state();
1803
1804     ensureBrush(brush);
1805     if (!s->brushData.blend)
1806         return;
1807
1808     fillRect(r, &s->brushData);
1809 }
1810
1811 /*!
1812     \reimp
1813 */
1814 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1815 {
1816 #ifdef QT_DEBUG_DRAW
1817     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1818 #endif
1819     Q_D(QRasterPaintEngine);
1820     QRasterPaintEngineState *s = state();
1821
1822     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1823     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1824         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1825         return;
1826     }
1827     d->solid_color_filler.clip = d->clip();
1828     d->solid_color_filler.adjustSpanMethods();
1829     fillRect(r, &d->solid_color_filler);
1830 }
1831
1832 static inline bool isAbove(const QPointF *a, const QPointF *b)
1833 {
1834     return a->y() < b->y();
1835 }
1836
1837 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1838 {
1839     Q_ASSERT(upper);
1840     Q_ASSERT(lower);
1841
1842     Q_ASSERT(pointCount >= 2);
1843
1844     QVector<const QPointF *> sorted;
1845     sorted.reserve(pointCount);
1846
1847     upper->reserve(pointCount * 3 / 4);
1848     lower->reserve(pointCount * 3 / 4);
1849
1850     for (int i = 0; i < pointCount; ++i)
1851         sorted << points + i;
1852
1853     qSort(sorted.begin(), sorted.end(), isAbove);
1854
1855     qreal splitY = sorted.at(sorted.size() / 2)->y();
1856
1857     const QPointF *end = points + pointCount;
1858     const QPointF *last = end - 1;
1859
1860     QVector<QPointF> *bin[2] = { upper, lower };
1861
1862     for (const QPointF *p = points; p < end; ++p) {
1863         int side = p->y() < splitY;
1864         int lastSide = last->y() < splitY;
1865
1866         if (side != lastSide) {
1867             if (qFuzzyCompare(p->y(), splitY)) {
1868                 bin[!side]->append(*p);
1869             } else if (qFuzzyCompare(last->y(), splitY)) {
1870                 bin[side]->append(*last);
1871             } else {
1872                 QPointF delta = *p - *last;
1873                 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1874
1875                 bin[0]->append(intersection);
1876                 bin[1]->append(intersection);
1877             }
1878         }
1879
1880         bin[side]->append(*p);
1881
1882         last = p;
1883     }
1884
1885     // give up if we couldn't reduce the point count
1886     return upper->size() < pointCount && lower->size() < pointCount;
1887 }
1888
1889 /*!
1890   \internal
1891  */
1892 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1893 {
1894     Q_D(QRasterPaintEngine);
1895     QRasterPaintEngineState *s = state();
1896
1897     const int maxPoints = 0xffff;
1898
1899     // max amount of points that raster engine can reliably handle
1900     if (pointCount > maxPoints) {
1901         QVector<QPointF> upper, lower;
1902
1903         if (splitPolygon(points, pointCount, &upper, &lower)) {
1904             fillPolygon(upper.constData(), upper.size(), mode);
1905             fillPolygon(lower.constData(), lower.size(), mode);
1906         } else
1907             qWarning("Polygon too complex for filling.");
1908
1909         return;
1910     }
1911
1912     // Compose polygon fill..,
1913     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1914     ensureOutlineMapper();
1915     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1916
1917     // scanconvert.
1918     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1919                                               &s->brushData);
1920     d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1921 }
1922
1923 /*!
1924     \reimp
1925 */
1926 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1927 {
1928     Q_D(QRasterPaintEngine);
1929     QRasterPaintEngineState *s = state();
1930
1931 #ifdef QT_DEBUG_DRAW
1932     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1933     for (int i=0; i<pointCount; ++i)
1934         qDebug() << "   - " << points[i];
1935 #endif
1936     Q_ASSERT(pointCount >= 2);
1937
1938     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1939         QRectF r(points[0], points[2]);
1940         drawRects(&r, 1);
1941         return;
1942     }
1943
1944     ensurePen();
1945     if (mode != PolylineMode) {
1946         // Do the fill...
1947         ensureBrush();
1948         if (s->brushData.blend) {
1949             d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
1950             fillPolygon(points, pointCount, mode);
1951             d->outlineMapper->setCoordinateRounding(false);
1952         }
1953     }
1954
1955     // Do the outline...
1956     if (s->penData.blend) {
1957         QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1958         if (s->flags.fast_pen) {
1959             QCosmeticStroker stroker(s, d->deviceRect);
1960             stroker.drawPath(vp);
1961         } else {
1962             QPaintEngineEx::stroke(vp, s->lastPen);
1963         }
1964     }
1965 }
1966
1967 /*!
1968     \reimp
1969 */
1970 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1971 {
1972     Q_D(QRasterPaintEngine);
1973     QRasterPaintEngineState *s = state();
1974
1975 #ifdef QT_DEBUG_DRAW
1976     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1977     for (int i=0; i<pointCount; ++i)
1978         qDebug() << "   - " << points[i];
1979 #endif
1980     Q_ASSERT(pointCount >= 2);
1981     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1982         QRect r(points[0].x(),
1983                 points[0].y(),
1984                 points[2].x() - points[0].x(),
1985                 points[2].y() - points[0].y());
1986         drawRects(&r, 1);
1987         return;
1988     }
1989
1990     ensurePen();
1991
1992     // Do the fill
1993     if (mode != PolylineMode) {
1994         ensureBrush();
1995         if (s->brushData.blend) {
1996             // Compose polygon fill..,
1997             ensureOutlineMapper();
1998             d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
1999             d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
2000             d->outlineMapper->moveTo(*points);
2001             const QPoint *p = points;
2002             const QPoint *ep = points + pointCount - 1;
2003             do {
2004                 d->outlineMapper->lineTo(*(++p));
2005             } while (p < ep);
2006             d->outlineMapper->endOutline();
2007
2008             // scanconvert.
2009             ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2010                                                       &s->brushData);
2011             d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
2012             d->outlineMapper->setCoordinateRounding(false);
2013         }
2014     }
2015
2016     // Do the outline...
2017     if (s->penData.blend) {
2018         int count = pointCount * 2;
2019         QVarLengthArray<qreal> fpoints(count);
2020         for (int i=0; i<count; ++i)
2021             fpoints[i] = ((int *) points)[i];
2022         QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2023
2024         if (s->flags.fast_pen) {
2025             QCosmeticStroker stroker(s, d->deviceRect);
2026             stroker.drawPath(vp);
2027         } else {
2028             QPaintEngineEx::stroke(vp, s->lastPen);
2029         }
2030     }
2031 }
2032
2033 /*!
2034     \internal
2035 */
2036 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2037 {
2038 #ifdef QT_DEBUG_DRAW
2039     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2040 #endif
2041
2042     QPixmapData *pd = pixmap.pixmapData();
2043     if (pd->classId() == QPixmapData::RasterClass) {
2044         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2045         if (image.depth() == 1) {
2046             Q_D(QRasterPaintEngine);
2047             QRasterPaintEngineState *s = state();
2048             if (s->matrix.type() <= QTransform::TxTranslate) {
2049                 ensurePen();
2050                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2051             } else {
2052                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2053             }
2054         } else {
2055             QRasterPaintEngine::drawImage(pos, image);
2056         }
2057     } else {
2058         const QImage image = pixmap.toImage();
2059         if (pixmap.depth() == 1) {
2060             Q_D(QRasterPaintEngine);
2061             QRasterPaintEngineState *s = state();
2062             if (s->matrix.type() <= QTransform::TxTranslate) {
2063                 ensurePen();
2064                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2065             } else {
2066                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2067             }
2068         } else {
2069             QRasterPaintEngine::drawImage(pos, image);
2070         }
2071     }
2072 }
2073
2074 /*!
2075     \reimp
2076 */
2077 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2078 {
2079 #ifdef QT_DEBUG_DRAW
2080     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2081 #endif
2082
2083     QPixmapData* pd = pixmap.pixmapData();
2084     if (pd->classId() == QPixmapData::RasterClass) {
2085         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2086         if (image.depth() == 1) {
2087             Q_D(QRasterPaintEngine);
2088             QRasterPaintEngineState *s = state();
2089             if (s->matrix.type() <= QTransform::TxTranslate
2090                 && r.size() == sr.size()
2091                 && r.size() == pixmap.size()) {
2092                 ensurePen();
2093                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2094                 return;
2095             } else {
2096                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2097             }
2098         } else {
2099             drawImage(r, image, sr);
2100         }
2101     } else {
2102         QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2103         const QImage image = pd->toImage(clippedSource);
2104         QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2105         if (image.depth() == 1) {
2106             Q_D(QRasterPaintEngine);
2107             QRasterPaintEngineState *s = state();
2108             if (s->matrix.type() <= QTransform::TxTranslate
2109                 && r.size() == sr.size()
2110                 && r.size() == pixmap.size()) {
2111                 ensurePen();
2112                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2113                 return;
2114             } else {
2115                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2116             }
2117         } else {
2118             drawImage(r, image, translatedSource);
2119         }
2120     }
2121 }
2122
2123 // assumes that rect has positive width and height
2124 static inline const QRect toRect_normalized(const QRectF &rect)
2125 {
2126     const int x = qRound(rect.x());
2127     const int y = qRound(rect.y());
2128     const int w = int(rect.width() + qreal(0.5));
2129     const int h = int(rect.height() + qreal(0.5));
2130
2131     return QRect(x, y, w, h);
2132 }
2133
2134 static inline int fast_ceil_positive(const qreal &v)
2135 {
2136     const int iv = int(v);
2137     if (v - iv == 0)
2138         return iv;
2139     else
2140         return iv + 1;
2141 }
2142
2143 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2144 {
2145     const int xmin = int(rect.x());
2146     const int xmax = int(fast_ceil_positive(rect.right()));
2147     const int ymin = int(rect.y());
2148     const int ymax = int(fast_ceil_positive(rect.bottom()));
2149     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2150 }
2151
2152 /*!
2153     \internal
2154 */
2155 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2156 {
2157 #ifdef QT_DEBUG_DRAW
2158     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
2159 #endif
2160
2161     Q_D(QRasterPaintEngine);
2162     QRasterPaintEngineState *s = state();
2163
2164     if (s->matrix.type() > QTransform::TxTranslate) {
2165         drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2166                   img,
2167                   QRectF(0, 0, img.width(), img.height()));
2168     } else {
2169
2170         const QClipData *clip = d->clip();
2171         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2172
2173         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2174             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2175             if (func) {
2176                 if (!clip) {
2177                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2178                     return;
2179                 } else if (clip->hasRectClip) {
2180                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2181                     return;
2182                 }
2183             }
2184         }
2185
2186
2187
2188         d->image_filler.clip = clip;
2189         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2190         if (!d->image_filler.blend)
2191             return;
2192         d->image_filler.dx = -pt.x();
2193         d->image_filler.dy = -pt.y();
2194         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2195
2196         fillRect_normalized(rr, &d->image_filler, d);
2197     }
2198
2199 }
2200
2201 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2202 {
2203     return QRectF(r.topLeft() * t, r.bottomRight() * t);
2204 }
2205
2206 namespace {
2207     enum RotationType {
2208         Rotation90,
2209         Rotation180,
2210         Rotation270,
2211         NoRotation
2212     };
2213
2214     inline RotationType qRotationType(const QTransform &transform)
2215     {
2216         QTransform::TransformationType type = transform.type();
2217
2218         if (type > QTransform::TxRotate)
2219             return NoRotation;
2220
2221         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2222             && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2223             return Rotation90;
2224
2225         if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2226             && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2227             return Rotation180;
2228
2229         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2230             && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2231             return Rotation270;
2232
2233         return NoRotation;
2234     }
2235
2236     inline bool isPixelAligned(const QRectF &rect) {
2237         return QRectF(rect.toRect()) == rect;
2238     }
2239 }
2240
2241 /*!
2242     \reimp
2243 */
2244 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2245                                    Qt::ImageConversionFlags)
2246 {
2247 #ifdef QT_DEBUG_DRAW
2248     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2249 #endif
2250
2251     if (r.isEmpty())
2252         return;
2253
2254     Q_D(QRasterPaintEngine);
2255     QRasterPaintEngineState *s = state();
2256     int sr_l = qFloor(sr.left());
2257     int sr_r = qCeil(sr.right()) - 1;
2258     int sr_t = qFloor(sr.top());
2259     int sr_b = qCeil(sr.bottom()) - 1;
2260
2261     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2262         // as fillRect will apply the aliased coordinate delta we need to
2263         // subtract it here as we don't use it for image drawing
2264         QTransform old = s->matrix;
2265         s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2266
2267         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2268         QRgb color = img.pixel(sr_l, sr_t);
2269         switch (img.format()) {
2270         case QImage::Format_ARGB32_Premultiplied:
2271         case QImage::Format_ARGB8565_Premultiplied:
2272         case QImage::Format_ARGB6666_Premultiplied:
2273         case QImage::Format_ARGB8555_Premultiplied:
2274         case QImage::Format_ARGB4444_Premultiplied:
2275             // Combine premultiplied color with the opacity set on the painter.
2276             d->solid_color_filler.solid.color =
2277                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2278                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2279             break;
2280         default:
2281             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2282             break;
2283         }
2284
2285         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2286             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2287             return;
2288         }
2289
2290         d->solid_color_filler.clip = d->clip();
2291         d->solid_color_filler.adjustSpanMethods();
2292         fillRect(r, &d->solid_color_filler);
2293
2294         s->matrix = old;
2295         return;
2296     }
2297
2298     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2299
2300     const QClipData *clip = d->clip();
2301
2302     if (s->matrix.type() > QTransform::TxTranslate
2303         && !stretch_sr
2304         && (!clip || clip->hasRectClip)
2305         && s->intOpacity == 256
2306         && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2307             || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2308         && d->rasterBuffer->format == img.format()
2309         && (d->rasterBuffer->format == QImage::Format_RGB16
2310             || d->rasterBuffer->format == QImage::Format_RGB32
2311             || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2312                 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2313     {
2314         RotationType rotationType = qRotationType(s->matrix);
2315
2316         if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2317             QRectF transformedTargetRect = s->matrix.mapRect(r);
2318
2319             if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2320                 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2321             {
2322                 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2323                 if (clippedTransformedTargetRect.isNull())
2324                     return;
2325
2326                 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2327
2328                 QRect clippedSourceRect
2329                     = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2330                             clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2331
2332                 uint dbpl = d->rasterBuffer->bytesPerLine();
2333                 uint sbpl = img.bytesPerLine();
2334
2335                 uchar *dst = d->rasterBuffer->buffer();
2336                 uint bpp = img.depth() >> 3;
2337
2338                 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2339                 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2340
2341                 uint cw = clippedSourceRect.width();
2342                 uint ch = clippedSourceRect.height();
2343
2344                 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2345
2346                 return;
2347             }
2348         }
2349     }
2350
2351     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2352
2353         QRectF targetBounds = s->matrix.mapRect(r);
2354         bool exceedsPrecision = targetBounds.width() > 0xffff
2355                                 || targetBounds.height() > 0xffff;
2356
2357         if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2358             if (s->matrix.type() > QTransform::TxScale) {
2359                 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2360                 if (func && (!clip || clip->hasRectClip)) {
2361                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2362                          img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2363                          s->matrix, s->intOpacity);
2364                     return;
2365                 }
2366             } else {
2367                 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2368                 if (func && (!clip || clip->hasRectClip)) {
2369                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2370                          img.bits(), img.bytesPerLine(),
2371                          qt_mapRect_non_normalizing(r, s->matrix), sr,
2372                          !clip ? d->deviceRect : clip->clipRect,
2373                          s->intOpacity);
2374                     return;
2375                 }
2376             }
2377         }
2378
2379         QTransform copy = s->matrix;
2380         copy.translate(r.x(), r.y());
2381         if (stretch_sr)
2382             copy.scale(r.width() / sr.width(), r.height() / sr.height());
2383         copy.translate(-sr.x(), -sr.y());
2384
2385         d->image_filler_xform.clip = clip;
2386         d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2387         if (!d->image_filler_xform.blend)
2388             return;
2389         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2390
2391         if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2392             QRectF rr = s->matrix.mapRect(r);
2393
2394             const int x1 = qRound(rr.x());
2395             const int y1 = qRound(rr.y());
2396             const int x2 = qRound(rr.right());
2397             const int y2 = qRound(rr.bottom());
2398
2399             fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2400             return;
2401         }
2402
2403 #ifdef QT_FAST_SPANS
2404         ensureState();
2405         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2406             d->initializeRasterizer(&d->image_filler_xform);
2407             d->rasterizer->setAntialiased(s->flags.antialiased);
2408
2409             const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2410
2411             const QRectF &rect = r.normalized();
2412             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2413             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2414
2415             if (s->flags.tx_noshear)
2416                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2417             else
2418                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2419             return;
2420         }
2421 #endif
2422         const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2423         QPainterPath path;
2424         path.addRect(r);
2425         QTransform m = s->matrix;
2426         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2427                                m.m21(), m.m22(), m.m23(),
2428                                m.m31() - offs, m.m32() - offs, m.m33());
2429         fillPath(path, &d->image_filler_xform);
2430         s->matrix = m;
2431     } else {
2432         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2433             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2434             if (func) {
2435                 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2436                 if (!clip) {
2437                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2438                     return;
2439                 } else if (clip->hasRectClip) {
2440                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2441                     return;
2442                 }
2443             }
2444         }
2445
2446         d->image_filler.clip = clip;
2447         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2448         if (!d->image_filler.blend)
2449             return;
2450         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2451         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2452
2453         QRectF rr = r;
2454         rr.translate(s->matrix.dx(), s->matrix.dy());
2455
2456         const int x1 = qRound(rr.x());
2457         const int y1 = qRound(rr.y());
2458         const int x2 = qRound(rr.right());
2459         const int y2 = qRound(rr.bottom());
2460
2461         fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2462     }
2463 }
2464
2465 /*!
2466     \reimp
2467 */
2468 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2469 {
2470 #ifdef QT_DEBUG_DRAW
2471     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2472 #endif
2473     Q_D(QRasterPaintEngine);
2474     QRasterPaintEngineState *s = state();
2475
2476     QImage image;
2477
2478     QPixmapData *pd = pixmap.pixmapData();
2479     if (pd->classId() == QPixmapData::RasterClass) {
2480         image = static_cast<QRasterPixmapData *>(pd)->image;
2481     } else {
2482         image = pixmap.toImage();
2483     }
2484
2485     if (image.depth() == 1)
2486         image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2487
2488     if (s->matrix.type() > QTransform::TxTranslate) {
2489         QTransform copy = s->matrix;
2490         copy.translate(r.x(), r.y());
2491         copy.translate(-sr.x(), -sr.y());
2492         d->image_filler_xform.clip = d->clip();
2493         d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2494         if (!d->image_filler_xform.blend)
2495             return;
2496         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2497
2498 #ifdef QT_FAST_SPANS
2499         ensureState();
2500         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2501             d->initializeRasterizer(&d->image_filler_xform);
2502             d->rasterizer->setAntialiased(s->flags.antialiased);
2503
2504             const QRectF &rect = r.normalized();
2505             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2506             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2507             if (s->flags.tx_noshear)
2508                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2509             else
2510                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2511             return;
2512         }
2513 #endif
2514         QPainterPath path;
2515         path.addRect(r);
2516         fillPath(path, &d->image_filler_xform);
2517     } else {
2518         d->image_filler.clip = d->clip();
2519
2520         d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2521         if (!d->image_filler.blend)
2522             return;
2523         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2524         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2525
2526         QRectF rr = r;
2527         rr.translate(s->matrix.dx(), s->matrix.dy());
2528         fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2529     }
2530 }
2531
2532
2533 //QWS hack
2534 static inline bool monoVal(const uchar* s, int x)
2535 {
2536     return  (s[x>>3] << (x&7)) & 0x80;
2537 }
2538
2539 /*!
2540     \internal
2541 */
2542 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2543 {
2544     Q_D(QRasterPaintEngine);
2545     QRasterPaintEngineState *s = state();
2546
2547     if (!s->penData.blend)
2548         return;
2549
2550     QRasterBuffer *rb = d->rasterBuffer.data();
2551
2552     const QRect rect(rx, ry, w, h);
2553     const QClipData *clip = d->clip();
2554     bool unclipped = false;
2555     if (clip) {
2556         // inlined QRect::intersects
2557         const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2558                                 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2559
2560         if (clip->hasRectClip) {
2561             unclipped = rx > clip->xmin
2562                         && rx + w < clip->xmax
2563                         && ry > clip->ymin
2564                         && ry + h < clip->ymax;
2565         }
2566
2567         if (!intersects)
2568             return;
2569     } else {
2570         // inlined QRect::intersects
2571         const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2572                                 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2573         if (!intersects)
2574             return;
2575
2576         // inlined QRect::contains
2577         const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2578                               && rect.top() >= 0 && rect.bottom() < rb->height();
2579
2580         unclipped = contains && d->isUnclipped_normalized(rect);
2581     }
2582
2583     ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2584     const uchar * scanline = static_cast<const uchar *>(src);
2585
2586     if (s->flags.fast_text) {
2587         if (unclipped) {
2588             if (depth == 1) {
2589                 if (s->penData.bitmapBlit) {
2590                     s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2591                                           scanline, w, h, bpl);
2592                     return;
2593                 }
2594             } else if (depth == 8) {
2595                 if (s->penData.alphamapBlit) {
2596                     s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2597                                             scanline, w, h, bpl, 0);
2598                     return;
2599                 }
2600             } else if (depth == 32) {
2601                 // (A)RGB Alpha mask where the alpha component is not used.
2602                 if (s->penData.alphaRGBBlit) {
2603                     s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2604                                             (const uint *) scanline, w, h, bpl / 4, 0);
2605                     return;
2606                 }
2607             }
2608         } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2609             // (A)RGB Alpha mask where the alpha component is not used.
2610             if (!clip) {
2611                 int nx = qMax(0, rx);
2612                 int ny = qMax(0, ry);
2613
2614                 // Move scanline pointer to compensate for moved x and y
2615                 int xdiff = nx - rx;
2616                 int ydiff = ny - ry;
2617                 scanline += ydiff * bpl;
2618                 scanline += xdiff * (depth == 32 ? 4 : 1);
2619
2620                 w -= xdiff;
2621                 h -= ydiff;
2622
2623                 if (nx + w > d->rasterBuffer->width())
2624                     w = d->rasterBuffer->width() - nx;
2625                 if (ny + h > d->rasterBuffer->height())
2626                     h = d->rasterBuffer->height() - ny;
2627
2628                 rx = nx;
2629                 ry = ny;
2630             }
2631             if (depth == 8 && s->penData.alphamapBlit) {
2632                 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2633                                         scanline, w, h, bpl, clip);
2634             } else if (depth == 32 && s->penData.alphaRGBBlit) {
2635                 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2636                                         (const uint *) scanline, w, h, bpl / 4, clip);
2637             }
2638             return;
2639         }
2640     }
2641
2642     int x0 = 0;
2643     if (rx < 0) {
2644         x0 = -rx;
2645         w -= x0;
2646     }
2647
2648     int y0 = 0;
2649     if (ry < 0) {
2650         y0 = -ry;
2651         scanline += bpl * y0;
2652         h -= y0;
2653     }
2654
2655     w = qMin(w, rb->width() - qMax(0, rx));
2656     h = qMin(h, rb->height() - qMax(0, ry));
2657
2658     if (w <= 0 || h <= 0)
2659         return;
2660
2661     const int NSPANS = 256;
2662     QSpan spans[NSPANS];
2663     int current = 0;
2664
2665     const int x1 = x0 + w;
2666     const int y1 = y0 + h;
2667
2668     if (depth == 1) {
2669         for (int y = y0; y < y1; ++y) {
2670             for (int x = x0; x < x1; ) {
2671                 if (!monoVal(scanline, x)) {
2672                     ++x;
2673                     continue;
2674                 }
2675
2676                 if (current == NSPANS) {
2677                     blend(current, spans, &s->penData);
2678                     current = 0;
2679                 }
2680                 spans[current].x = x + rx;
2681                 spans[current].y = y + ry;
2682                 spans[current].coverage = 255;
2683                 int len = 1;
2684                 ++x;
2685                 // extend span until we find a different one.
2686                 while (x < x1 && monoVal(scanline, x)) {
2687                     ++x;
2688                     ++len;
2689                 }
2690                 spans[current].len = len;
2691                 ++current;
2692             }
2693             scanline += bpl;
2694         }
2695     } else if (depth == 8) {
2696         for (int y = y0; y < y1; ++y) {
2697             for (int x = x0; x < x1; ) {
2698                 // Skip those with 0 coverage
2699                 if (scanline[x] == 0) {
2700                     ++x;
2701                     continue;
2702                 }
2703
2704                 if (current == NSPANS) {
2705                     blend(current, spans, &s->penData);
2706                     current = 0;
2707                 }
2708                 int coverage = scanline[x];
2709                 spans[current].x = x + rx;
2710                 spans[current].y = y + ry;
2711                 spans[current].coverage = coverage;
2712                 int len = 1;
2713                 ++x;
2714
2715                 // extend span until we find a different one.
2716                 while (x < x1 && scanline[x] == coverage) {
2717                     ++x;
2718                     ++len;
2719                 }
2720                 spans[current].len = len;
2721                 ++current;
2722             }
2723             scanline += bpl;
2724         }
2725     } else { // 32-bit alpha...
2726         uint *sl = (uint *) src;
2727         for (int y = y0; y < y1; ++y) {
2728             for (int x = x0; x < x1; ) {
2729                 // Skip those with 0 coverage
2730                 if ((sl[x] & 0x00ffffff) == 0) {
2731                     ++x;
2732                     continue;
2733                 }
2734
2735                 if (current == NSPANS) {
2736                     blend(current, spans, &s->penData);
2737                     current = 0;
2738                 }
2739                 uint rgbCoverage = sl[x];
2740                 int coverage = qGreen(rgbCoverage);
2741                 spans[current].x = x + rx;
2742                 spans[current].y = y + ry;
2743                 spans[current].coverage = coverage;
2744                 int len = 1;
2745                 ++x;
2746
2747                 // extend span until we find a different one.
2748                 while (x < x1 && sl[x] == rgbCoverage) {
2749                     ++x;
2750                     ++len;
2751                 }
2752                 spans[current].len = len;
2753                 ++current;
2754             }
2755             sl += bpl / sizeof(uint);
2756         }
2757     }
2758 //     qDebug() << "alphaPenBlt: num spans=" << current
2759 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2760         // Call span func for current set of spans.
2761     if (current != 0)
2762         blend(current, spans, &s->penData);
2763 }
2764
2765 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2766                                           const QFixedPoint *positions, QFontEngine *fontEngine)
2767 {
2768     Q_D(QRasterPaintEngine);
2769     QRasterPaintEngineState *s = state();
2770
2771 #if !defined(QT_NO_FREETYPE)
2772     if (fontEngine->type() == QFontEngine::Freetype) {
2773         QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
2774         QFontEngineFT::GlyphFormat neededFormat =
2775             painter()->device()->devType() == QInternal::Widget
2776             ? fe->defaultGlyphFormat()
2777             : QFontEngineFT::Format_A8;
2778
2779         if (d_func()->mono_surface
2780             || fe->isBitmapFont() // alphaPenBlt can handle mono, too
2781             )
2782             neededFormat = QFontEngineFT::Format_Mono;
2783
2784         if (neededFormat == QFontEngineFT::Format_None)
2785             neededFormat = QFontEngineFT::Format_A8;
2786
2787         QFontEngineFT::QGlyphSet *gset = fe->defaultGlyphs();
2788         if (s->matrix.type() >= QTransform::TxScale) {
2789             if (s->matrix.isAffine())
2790                 gset = fe->loadTransformedGlyphSet(s->matrix);
2791             else
2792                 gset = 0;
2793         }
2794
2795         if (!gset || gset->outline_drawing
2796             || !fe->loadGlyphs(gset, glyphs, numGlyphs, positions, neededFormat))
2797             return false;
2798
2799         FT_Face lockedFace = 0;
2800
2801         int depth;
2802         switch (neededFormat) {
2803         case QFontEngineFT::Format_Mono:
2804             depth = 1;
2805             break;
2806         case QFontEngineFT::Format_A8:
2807             depth = 8;
2808             break;
2809         case QFontEngineFT::Format_A32:
2810             depth = 32;
2811             break;
2812         default:
2813             Q_ASSERT(false);
2814             depth = 0;
2815         };
2816
2817         for (int i = 0; i < numGlyphs; i++) {
2818             QFixed spp = fe->subPixelPositionForX(positions[i].x);
2819             QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphs[i], spp);
2820
2821             if (!glyph || glyph->format != neededFormat) {
2822                 if (!lockedFace)
2823                     lockedFace = fe->lockFace();
2824                 glyph = fe->loadGlyph(gset, glyphs[i], spp, neededFormat);
2825             }
2826
2827             if (!glyph || !glyph->data)
2828                 continue;
2829
2830             int pitch;
2831             switch (neededFormat) {
2832             case QFontEngineFT::Format_Mono:
2833                 pitch = ((glyph->width + 31) & ~31) >> 3;
2834                 break;
2835             case QFontEngineFT::Format_A8:
2836                 pitch = (glyph->width + 3) & ~3;
2837                 break;
2838             case QFontEngineFT::Format_A32:
2839                 pitch = glyph->width * 4;
2840                 break;
2841             default:
2842                 Q_ASSERT(false);
2843                 pitch = 0;
2844             };
2845
2846             alphaPenBlt(glyph->data, pitch, depth,
2847                         qFloor(positions[i].x) + glyph->x,
2848                         qFloor(positions[i].y) - glyph->y,
2849                         glyph->width, glyph->height);
2850         }
2851         if (lockedFace)
2852             fe->unlockFace();
2853     } else
2854 #endif
2855     {
2856         QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2857
2858         QImageTextureGlyphCache *cache =
2859             static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2860         if (!cache) {
2861             cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2862             fontEngine->setGlyphCache(0, cache);
2863         }
2864
2865         cache->populate(fontEngine, numGlyphs, glyphs, positions);
2866         cache->fillInPendingGlyphs();
2867
2868         const QImage &image = cache->image();
2869         int bpl = image.bytesPerLine();
2870
2871         int depth = image.depth();
2872         int rightShift = 0;
2873         int leftShift = 0;
2874         if (depth == 32)
2875             leftShift = 2; // multiply by 4
2876         else if (depth == 1)
2877             rightShift = 3; // divide by 8
2878
2879         int margin = cache->glyphMargin();
2880         const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
2881         const uchar *bits = image.bits();
2882         for (int i=0; i<numGlyphs; ++i) {
2883
2884             QFixed subPixelPosition = cache->subPixelPositionForX(positions[i].x);
2885             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2886             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2887             if (c.isNull())
2888                 continue;
2889
2890             int x = qFloor(positions[i].x + offs) + c.baseLineX - margin;
2891             int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
2892
2893             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2894             //        c.x, c.y,
2895             //        c.w, c.h,
2896             //        c.baseLineX, c.baseLineY,
2897             //        glyphs[i],
2898             //        x, y,
2899             //        positions[i].x.toInt(), positions[i].y.toInt());
2900
2901             alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2902         }
2903     }
2904     return true;
2905 }
2906
2907 #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
2908 void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
2909 {
2910     Q_D(QRasterPaintEngine);
2911     QRasterPaintEngineState *s = state();
2912
2913     QFontEngine *fontEngine = ti.fontEngine;
2914     if (fontEngine->type() != QFontEngine::S60FontEngine) {
2915         QPaintEngineEx::drawTextItem(p, ti);
2916         return;
2917     }
2918
2919     QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
2920
2921     QVarLengthArray<QFixedPoint> positions;
2922     QVarLengthArray<glyph_t> glyphs;
2923     QTransform matrix = s->matrix;
2924     matrix.translate(p.x(), p.y());
2925     if (matrix.type() == QTransform::TxScale)
2926         fe->setFontScale(matrix.m11());
2927     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
2928
2929     const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
2930
2931     for (int i=0; i<glyphs.size(); ++i) {
2932         TOpenFontCharMetrics tmetrics;
2933         const TUint8 *glyphBitmapBytes;
2934         TSize glyphBitmapSize;
2935         fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
2936         const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta);
2937         const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
2938         alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
2939     }
2940
2941     if (matrix.type() == QTransform::TxScale)
2942         fe->setFontScale(1.0);
2943
2944     return;
2945 }
2946 #endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
2947
2948 /*!
2949  * Returns true if the rectangle is completely within the current clip
2950  * state of the paint engine.
2951  */
2952 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2953 {
2954     const QClipData *cl = clip();
2955     if (!cl) {
2956         // inline contains() for performance (we know the rects are normalized)
2957         const QRect &r1 = deviceRect;
2958         return (r.left() >= r1.left() && r.right() <= r1.right()
2959                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2960     }
2961
2962
2963     if (cl->hasRectClip) {
2964         // currently all painting functions clips to deviceRect internally
2965         if (cl->clipRect == deviceRect)
2966             return true;
2967
2968         // inline contains() for performance (we know the rects are normalized)
2969         const QRect &r1 = cl->clipRect;
2970         return (r.left() >= r1.left() && r.right() <= r1.right()
2971                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2972     } else {
2973         return qt_region_strictContains(cl->clipRegion, r);
2974     }
2975 }
2976
2977 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2978                                             int penWidth) const
2979 {
2980     Q_Q(const QRasterPaintEngine);
2981     const QRasterPaintEngineState *s = q->state();
2982     const QClipData *cl = clip();
2983     if (!cl) {
2984         QRect r = rect.normalized();
2985         // inline contains() for performance (we know the rects are normalized)
2986         const QRect &r1 = deviceRect;
2987         return (r.left() >= r1.left() && r.right() <= r1.right()
2988                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2989     }
2990
2991
2992     // currently all painting functions that call this function clip to deviceRect internally
2993     if (cl->hasRectClip && cl->clipRect == deviceRect)
2994         return true;
2995
2996     if (s->flags.antialiased)
2997         ++penWidth;
2998
2999     QRect r = rect.normalized();
3000     if (penWidth > 0) {
3001         r.setX(r.x() - penWidth);
3002         r.setY(r.y() - penWidth);
3003         r.setWidth(r.width() + 2 * penWidth);
3004         r.setHeight(r.height() + 2 * penWidth);
3005     }
3006
3007     if (cl->hasRectClip) {
3008         // inline contains() for performance (we know the rects are normalized)
3009         const QRect &r1 = cl->clipRect;
3010         return (r.left() >= r1.left() && r.right() <= r1.right()
3011                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
3012     } else {
3013         return qt_region_strictContains(cl->clipRegion, r);
3014     }
3015 }
3016
3017 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
3018                                                    int penWidth) const
3019 {
3020     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
3021 }
3022
3023 inline ProcessSpans
3024 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
3025                                         const QSpanData *data) const
3026 {
3027     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3028 }
3029
3030 inline ProcessSpans
3031 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
3032                                         const QSpanData *data) const
3033 {
3034     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
3035 }
3036
3037 inline ProcessSpans
3038 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
3039                                       const QSpanData *data) const
3040 {
3041     Q_Q(const QRasterPaintEngine);
3042     const QRasterPaintEngineState *s = q->state();
3043
3044     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
3045         return data->blend;
3046     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
3047     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
3048 }
3049
3050 /*!
3051    \reimp
3052 */
3053 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3054 {
3055     ensurePen();
3056     ensureState();
3057
3058     QFontEngine *fontEngine = textItem->fontEngine();
3059     if (!supportsTransformations(fontEngine)) {
3060         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3061                          fontEngine);
3062     } else {
3063         QPaintEngineEx::drawStaticTextItem(textItem);
3064     }
3065 }
3066
3067 /*!
3068     \reimp
3069 */
3070 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3071 {
3072     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3073     QRasterPaintEngineState *s = state();
3074
3075 #ifdef QT_DEBUG_DRAW
3076     Q_D(QRasterPaintEngine);
3077     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3078            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3079            d->glyphCacheType);
3080 #endif
3081
3082     ensurePen();
3083     ensureState();
3084
3085 #if defined (Q_WS_WIN) || defined(Q_WS_MAC)
3086
3087     if (!supportsTransformations(ti.fontEngine)) {
3088         QVarLengthArray<QFixedPoint> positions;
3089         QVarLengthArray<glyph_t> glyphs;
3090
3091         QTransform matrix = s->matrix;
3092         matrix.translate(p.x(), p.y());
3093
3094         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3095
3096         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3097         return;
3098     }
3099
3100 #elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
3101     if (s->matrix.type() <= QTransform::TxTranslate
3102         || (s->matrix.type() == QTransform::TxScale
3103                 && (qFuzzyCompare(s->matrix.m11(), s->matrix.m22())))) {
3104         drawGlyphsS60(p, ti);
3105         return;
3106     }
3107 #else // Q_WS_WIN || Q_WS_MAC
3108
3109     QFontEngine *fontEngine = ti.fontEngine;
3110
3111 #if defined(Q_WS_QWS)
3112     if (fontEngine->type() == QFontEngine::Box) {
3113         fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
3114         return;
3115     }
3116
3117     if (s->matrix.type() < QTransform::TxScale
3118         && (fontEngine->type() == QFontEngine::QPF1 || fontEngine->type() == QFontEngine::QPF2
3119             || (fontEngine->type() == QFontEngine::Proxy
3120                 && !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
3121             )) {
3122         fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
3123         return;
3124     }
3125 #endif // Q_WS_QWS
3126
3127 #ifdef Q_WS_QPA
3128     if (s->matrix.type() < QTransform::TxScale) {
3129
3130         QVarLengthArray<QFixedPoint> positions;
3131         QVarLengthArray<glyph_t> glyphs;
3132         QTransform matrix = state()->transform();
3133
3134         qreal _x = qFloor(p.x());
3135         qreal _y = qFloor(p.y());
3136         matrix.translate(_x, _y);
3137
3138         fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3139         if (glyphs.size() == 0)
3140             return;
3141
3142         for(int i = 0; i < glyphs.size(); i++) {
3143             QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
3144             glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
3145             // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
3146             alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
3147                                          qRound(positions[i].x + metrics.x),
3148                                          qRound(positions[i].y + metrics.y),
3149                                          img.width(), img.height());
3150         }
3151         return;
3152     }
3153 #endif //Q_WS_QPA
3154
3155 #if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3156
3157 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3158     if (fontEngine->type() == QFontEngine::QPF2) {
3159         QFontEngine *renderingEngine = static_cast<QFontEngineQPF *>(fontEngine)->renderingEngine();
3160         if (renderingEngine)
3161             fontEngine = renderingEngine;
3162     }
3163 #endif
3164
3165     if (fontEngine->type() != QFontEngine::Freetype) {
3166         QPaintEngineEx::drawTextItem(p, ti);
3167         return;
3168     }
3169
3170     QFontEngineFT *fe = static_cast<QFontEngineFT *>(fontEngine);
3171
3172     QTransform matrix = s->matrix;
3173     matrix.translate(p.x(), p.y());
3174
3175     QVarLengthArray<QFixedPoint> positions;
3176     QVarLengthArray<glyph_t> glyphs;
3177     fe->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3178     if (glyphs.size() == 0)
3179         return;
3180
3181     if (!drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), fontEngine))
3182         QPaintEngine::drawTextItem(p, ti);
3183
3184     return;
3185 #endif
3186 #endif
3187
3188     QPaintEngineEx::drawTextItem(p, ti);
3189 }
3190
3191 /*!
3192     \reimp
3193 */
3194 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3195 {
3196     Q_D(QRasterPaintEngine);
3197     QRasterPaintEngineState *s = state();
3198
3199     ensurePen();
3200     if (!s->penData.blend)
3201         return;
3202
3203     if (!s->flags.fast_pen) {
3204         QPaintEngineEx::drawPoints(points, pointCount);
3205         return;
3206     }
3207
3208     QCosmeticStroker stroker(s, d->deviceRect);
3209     stroker.drawPoints(points, pointCount);
3210 }
3211
3212
3213 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3214 {
3215     Q_D(QRasterPaintEngine);
3216     QRasterPaintEngineState *s = state();
3217
3218     ensurePen();
3219     if (!s->penData.blend)
3220         return;
3221
3222     if (!s->flags.fast_pen) {
3223         QPaintEngineEx::drawPoints(points, pointCount);
3224         return;
3225     }
3226
3227     QCosmeticStroker stroker(s, d->deviceRect);
3228     stroker.drawPoints(points, pointCount);
3229 }
3230
3231 /*!
3232     \reimp
3233 */
3234 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3235 {
3236 #ifdef QT_DEBUG_DRAW
3237     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3238 #endif
3239     Q_D(QRasterPaintEngine);
3240     QRasterPaintEngineState *s = state();
3241
3242     ensurePen();
3243     if (!s->penData.blend)
3244         return;
3245
3246     if (s->flags.fast_pen) {
3247         QCosmeticStroker stroker(s, d->deviceRect);
3248         for (int i=0; i<lineCount; ++i) {
3249             const QLine &l = lines[i];
3250             stroker.drawLine(l.p1(), l.p2());
3251         }
3252     } else {
3253         QPaintEngineEx::drawLines(lines, lineCount);
3254     }
3255 }
3256
3257 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3258                                                      qreal width,
3259                                                      int *dashIndex,
3260                                                      qreal *dashOffset,
3261                                                      bool *inDash)
3262 {
3263     Q_Q(QRasterPaintEngine);
3264     QRasterPaintEngineState *s = q->state();
3265
3266     const QPen &pen = s->lastPen;
3267     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3268     const QVector<qreal> pattern = pen.dashPattern();
3269
3270     qreal patternLength = 0;
3271     for (int i = 0; i < pattern.size(); ++i)
3272         patternLength += pattern.at(i);
3273
3274     if (patternLength <= 0)
3275         return;
3276
3277     qreal length = line.length();
3278     Q_ASSERT(length > 0);
3279     while (length > 0) {
3280         const bool rasterize = *inDash;
3281         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3282         QLineF l = line;
3283
3284         if (dash >= length) {
3285             dash = length;
3286             *dashOffset += dash / width;
3287             length = 0;
3288         } else {
3289             *dashOffset = 0;
3290             *inDash = !(*inDash);
3291             if (++*dashIndex >= pattern.size())
3292                 *dashIndex = 0;
3293             length -= dash;
3294             l.setLength(dash);
3295             line.setP1(l.p2());
3296         }
3297
3298         if (rasterize && dash > 0)
3299             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3300     }
3301 }
3302
3303 /*!
3304     \reimp
3305 */
3306 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3307 {
3308 #ifdef QT_DEBUG_DRAW
3309     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3310 #endif
3311     Q_D(QRasterPaintEngine);
3312     QRasterPaintEngineState *s = state();
3313
3314     ensurePen();
3315     if (!s->penData.blend)
3316         return;
3317     if (s->flags.fast_pen) {
3318         QCosmeticStroker stroker(s, d->deviceRect);
3319         for (int i=0; i<lineCount; ++i) {
3320             QLineF line = lines[i];
3321             stroker.drawLine(line.p1(), line.p2());
3322         }
3323     } else {
3324         QPaintEngineEx::drawLines(lines, lineCount);
3325     }
3326 }
3327
3328
3329 /*!
3330     \reimp
3331 */
3332 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3333 {
3334     Q_D(QRasterPaintEngine);
3335     QRasterPaintEngineState *s = state();
3336
3337     ensurePen();
3338     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3339            || (qpen_style(s->lastPen) == Qt::NoPen))
3340         && !s->flags.antialiased
3341         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3342         && !rect.isEmpty()
3343         && s->matrix.type() <= QTransform::TxScale) // no shear
3344     {
3345         ensureBrush();
3346         const QRectF r = s->matrix.mapRect(rect);
3347         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3348         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3349         const QRect brect = QRect(int(r.x()), int(r.y()),
3350                                   int_dim(r.x(), r.width()),
3351                                   int_dim(r.y(), r.height()));
3352         if (brect == r) {
3353             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3354                                    &s->penData, &s->brushData);
3355             return;
3356         }
3357     }
3358     QPaintEngineEx::drawEllipse(rect);
3359 }
3360
3361 /*!
3362     \internal
3363 */
3364 #ifdef Q_WS_MAC
3365 void QRasterPaintEngine::setCGContext(CGContextRef ctx)
3366 {
3367     Q_D(QRasterPaintEngine);
3368     d->cgContext = ctx;
3369 }
3370
3371 /*!
3372     \internal
3373 */
3374 CGContextRef QRasterPaintEngine::getCGContext() const
3375 {
3376     Q_D(const QRasterPaintEngine);
3377     return d->cgContext;
3378 }
3379 #endif
3380
3381 #ifdef Q_WS_WIN
3382 /*!
3383     \internal
3384 */
3385 void QRasterPaintEngine::setDC(HDC hdc) {
3386     Q_D(QRasterPaintEngine);
3387     d->hdc = hdc;
3388 }
3389
3390 /*!
3391     \internal
3392 */
3393 HDC QRasterPaintEngine::getDC() const
3394 {
3395     Q_D(const QRasterPaintEngine);
3396     return d->hdc;
3397 }
3398
3399 /*!
3400     \internal
3401 */
3402 void QRasterPaintEngine::releaseDC(HDC) const
3403 {
3404 }
3405
3406 #endif
3407
3408 bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
3409 {
3410     const QTransform &m = state()->matrix;
3411 #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3412     QFontEngine::Type fontEngineType = fontEngine->type();
3413     if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
3414         || (m.type() <= QTransform::TxTranslate
3415             && (fontEngineType == QFontEngine::TestFontEngine
3416                 || fontEngineType == QFontEngine::Box))) {
3417             return true;
3418     }
3419 #endif
3420     return supportsTransformations(fontEngine->fontDef.pixelSize, m);
3421 }
3422
3423 bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
3424 {
3425 #if defined(Q_WS_MAC)
3426     // Mac font engines don't support scaling and rotation
3427     if (m.type() > QTransform::TxTranslate)
3428 #else
3429     if (m.type() >= QTransform::TxProject)
3430 #endif
3431         return true;
3432
3433     if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
3434         return true;
3435
3436     return false;
3437 }
3438
3439 /*!
3440     \internal
3441 */
3442 QPoint QRasterPaintEngine::coordinateOffset() const
3443 {
3444     return QPoint(0, 0);
3445 }
3446
3447 /*!
3448     Draws the given color \a spans with the specified \a color. The \a
3449     count parameter specifies the number of spans.
3450
3451     The default implementation does nothing; reimplement this function
3452     to draw the given color \a spans with the specified \a color. Note
3453     that this function \e must be reimplemented if the framebuffer is
3454     not memory-mapped.
3455
3456     \sa drawBufferSpan()
3457 */
3458 #if defined(Q_WS_QWS) && !defined(QT_NO_RASTERCALLBACKS)
3459 void QRasterPaintEngine::drawColorSpans(const QSpan *spans, int count, uint color)
3460 {
3461     Q_UNUSED(spans);
3462     Q_UNUSED(count);
3463     Q_UNUSED(color);
3464     qFatal("QRasterPaintEngine::drawColorSpans must be reimplemented on "
3465            "a non memory-mapped device");
3466 }
3467
3468 /*!
3469     \fn void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int size, int x, int y, int length, uint alpha)
3470
3471     Draws the given \a buffer.
3472
3473     The default implementation does nothing; reimplement this function
3474     to draw a buffer that contains more than one color. Note that this
3475     function \e must be reimplemented if the framebuffer is not
3476     memory-mapped.
3477
3478     The \a size parameter specifies the total size of the given \a
3479     buffer, while the \a length parameter specifies the number of
3480     pixels to draw. The buffer's position is given by (\a x, \a
3481     y). The provided \a alpha value is added to each pixel in the
3482     buffer when drawing.
3483
3484     \sa drawColorSpans()
3485 */
3486 void QRasterPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
3487                                         int x, int y, int length, uint const_alpha)
3488 {
3489     Q_UNUSED(buffer);
3490     Q_UNUSED(bufsize);
3491     Q_UNUSED(x);
3492     Q_UNUSED(y);
3493     Q_UNUSED(length);
3494     Q_UNUSED(const_alpha);
3495     qFatal("QRasterPaintEngine::drawBufferSpan must be reimplemented on "
3496            "a non memory-mapped device");
3497 }
3498 #endif // Q_WS_QWS
3499
3500 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3501 {
3502     Q_ASSERT(fg);
3503     if (!fg->blend)
3504         return;
3505     Q_D(QRasterPaintEngine);
3506
3507     Q_ASSERT(image.depth() == 1);
3508
3509     const int spanCount = 256;
3510     QT_FT_Span spans[spanCount];
3511     int n = 0;
3512
3513     // Boundaries
3514     int w = image.width();
3515     int h = image.height();
3516     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3517     int ymin = qMax(qRound(pos.y()), 0);
3518     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3519     int xmin = qMax(qRound(pos.x()), 0);
3520
3521     int x_offset = xmin - qRound(pos.x());
3522
3523     QImage::Format format = image.format();
3524     for (int y = ymin; y < ymax; ++y) {
3525         const uchar *src = image.scanLine(y - qRound(pos.y()));
3526         if (format == QImage::Format_MonoLSB) {
3527             for (int x = 0; x < xmax - xmin; ++x) {
3528                 int src_x = x + x_offset;
3529                 uchar pixel = src[src_x >> 3];
3530                 if (!pixel) {
3531                     x += 7 - (src_x%8);
3532                     continue;
3533                 }
3534                 if (pixel & (0x1 << (src_x & 7))) {
3535                     spans[n].x = xmin + x;
3536                     spans[n].y = y;
3537                     spans[n].coverage = 255;
3538                     int len = 1;
3539                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3540                         ++src_x;
3541                         ++len;
3542                     }
3543                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3544                     x += len;
3545                     ++n;
3546                     if (n == spanCount) {
3547                         fg->blend(n, spans, fg);
3548                         n = 0;
3549                     }
3550                 }
3551             }
3552         } else {
3553             for (int x = 0; x < xmax - xmin; ++x) {
3554                 int src_x = x + x_offset;
3555                 uchar pixel = src[src_x >> 3];
3556                 if (!pixel) {
3557                     x += 7 - (src_x%8);
3558                     continue;
3559                 }
3560                 if (pixel & (0x80 >> (x & 7))) {
3561                     spans[n].x = xmin + x;
3562                     spans[n].y = y;
3563                     spans[n].coverage = 255;
3564                     int len = 1;
3565                     while (src_x < w-1 && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3566                         ++src_x;
3567                         ++len;
3568                     }
3569                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3570                     x += len;
3571                     ++n;
3572                     if (n == spanCount) {
3573                         fg->blend(n, spans, fg);
3574                         n = 0;
3575                     }
3576                 }
3577             }
3578         }
3579     }
3580     if (n) {
3581         fg->blend(n, spans, fg);
3582         n = 0;
3583     }
3584 }
3585
3586 /*!
3587     \enum QRasterPaintEngine::ClipType
3588     \internal
3589
3590     \value RectClip Indicates that the currently set clip is a single rectangle.
3591     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3592 */
3593
3594 /*!
3595     \internal
3596     Returns the type of the clip currently set.
3597 */
3598 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3599 {
3600     Q_D(const QRasterPaintEngine);
3601
3602     const QClipData *clip = d->clip();
3603     if (!clip || clip->hasRectClip)
3604         return RectClip;
3605     else
3606         return ComplexClip;
3607 }
3608
3609 /*!
3610     \internal
3611     Returns the bounding rect of the currently set clip.
3612 */
3613 QRect QRasterPaintEngine::clipBoundingRect() const
3614 {
3615     Q_D(const QRasterPaintEngine);
3616
3617     const QClipData *clip = d->clip();
3618
3619     if (!clip)
3620         return d->deviceRect;
3621
3622     if (clip->hasRectClip)
3623         return clip->clipRect;
3624
3625     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3626 }
3627
3628 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result)
3629 {
3630     Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3631
3632     QVarLengthArray<short, 4096> buffer;
3633
3634     QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3635     QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3636     result->initialize();
3637
3638     for (int y = 0; y < c1->clipSpanHeight; ++y) {
3639         const QSpan *c1_spans = c1ClipLines[y].spans;
3640         int c1_count = c1ClipLines[y].count;
3641         const QSpan *c2_spans = c2ClipLines[y].spans;
3642         int c2_count = c2ClipLines[y].count;
3643
3644         if (c1_count == 0 && c2_count == 0)
3645             continue;
3646         if (c1_count == 0) {
3647             result->appendSpans(c2_spans, c2_count);
3648             continue;
3649         } else if (c2_count == 0) {
3650             result->appendSpans(c1_spans, c1_count);
3651             continue;
3652         }
3653
3654         // we need to merge the two
3655
3656         // find required length
3657         int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3658                 c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3659         buffer.resize(max);
3660         memset(buffer.data(), 0, buffer.size() * sizeof(short));
3661
3662         // Fill with old spans.
3663         for (int i = 0; i < c1_count; ++i) {
3664             const QSpan *cs = c1_spans + i;
3665             for (int j=cs->x; j<cs->x + cs->len; ++j)
3666                 buffer[j] = cs->coverage;
3667         }
3668
3669         // Fill with new spans
3670         for (int i = 0; i < c2_count; ++i) {
3671             const QSpan *cs = c2_spans + i;
3672             for (int j = cs->x; j < cs->x + cs->len; ++j) {
3673                 buffer[j] += cs->coverage;
3674                 if (buffer[j] > 255)
3675                     buffer[j] = 255;
3676             }
3677         }
3678
3679         int x = 0;
3680         while (x<max) {
3681
3682             // Skip to next span
3683             while (x < max && buffer[x] == 0) ++x;
3684             if (x >= max) break;
3685
3686             int sx = x;
3687             int coverage = buffer[x];
3688
3689             // Find length of span
3690             while (x < max && buffer[x] == coverage)
3691                 ++x;
3692
3693             result->appendSpan(sx, x - sx, y, coverage);
3694         }
3695     }
3696 }
3697
3698 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3699 {
3700     Q_Q(QRasterPaintEngine);
3701     QRasterPaintEngineState *s = q->state();
3702
3703     rasterizer->setAntialiased(s->flags.antialiased);
3704
3705     QRect clipRect(deviceRect);
3706     ProcessSpans blend;
3707     // ### get from optimized rectbased QClipData
3708
3709     const QClipData *c = clip();
3710     if (c) {
3711         const QRect r(QPoint(c->xmin, c->ymin),
3712                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3713         clipRect = clipRect.intersected(r);
3714         blend = data->blend;
3715     } else {
3716         blend = data->unclipped_blend;
3717     }
3718
3719     rasterizer->setClipRect(clipRect);
3720     rasterizer->initialize(blend, data);
3721 }
3722
3723 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3724                                           ProcessSpans callback,
3725                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3726 {
3727     if (!callback || !outline)
3728         return;
3729
3730     Q_Q(QRasterPaintEngine);
3731     QRasterPaintEngineState *s = q->state();
3732
3733     if (!s->flags.antialiased) {
3734         initializeRasterizer(spanData);
3735
3736         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3737                                       ? Qt::WindingFill
3738                                       : Qt::OddEvenFill;
3739
3740         rasterizer->rasterize(outline, fillRule);
3741         return;
3742     }
3743
3744     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3745 }
3746
3747 extern "C" {
3748     int q_gray_rendered_spans(QT_FT_Raster raster);
3749 }
3750
3751 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3752                                           ProcessSpans callback,
3753                                           void *userData, QRasterBuffer *)
3754 {
3755     if (!callback || !outline)
3756         return;
3757
3758     Q_Q(QRasterPaintEngine);
3759     QRasterPaintEngineState *s = q->state();
3760
3761     if (!s->flags.antialiased) {
3762         rasterizer->setAntialiased(s->flags.antialiased);
3763         rasterizer->setClipRect(deviceRect);
3764         rasterizer->initialize(callback, userData);
3765
3766         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3767                                       ? Qt::WindingFill
3768                                       : Qt::OddEvenFill;
3769
3770         rasterizer->rasterize(outline, fillRule);
3771         return;
3772     }
3773
3774     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3775     // minimize memory reallocations. However if initial size for
3776     // raster pool is changed for lower value, reallocations will
3777     // occur normally.
3778     const int rasterPoolInitialSize = MINIMUM_POOL_SIZE;
3779     int rasterPoolSize = rasterPoolInitialSize;
3780     unsigned char *rasterPoolBase;
3781 #if defined(Q_WS_WIN64)
3782     rasterPoolBase =
3783         // We make use of setjmp and longjmp in qgrayraster.c which requires
3784         // 16-byte alignment, hence we hardcode this requirement here..
3785         (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3786 #else
3787     unsigned char rasterPoolOnStack[rasterPoolInitialSize];
3788     rasterPoolBase = rasterPoolOnStack;
3789 #endif
3790     Q_CHECK_PTR(rasterPoolBase);
3791
3792     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3793
3794     void *data = userData;
3795
3796     QT_FT_BBox clip_box = { deviceRect.x(),
3797                             deviceRect.y(),
3798                             deviceRect.x() + deviceRect.width(),
3799                             deviceRect.y() + deviceRect.height() };
3800
3801     QT_FT_Raster_Params rasterParams;
3802     rasterParams.target = 0;
3803     rasterParams.source = outline;
3804     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3805     rasterParams.gray_spans = 0;
3806     rasterParams.black_spans = 0;
3807     rasterParams.bit_test = 0;
3808     rasterParams.bit_set = 0;
3809     rasterParams.user = data;
3810     rasterParams.clip_box = clip_box;
3811
3812     bool done = false;
3813     int error;
3814
3815     int rendered_spans = 0;
3816
3817     while (!done) {
3818
3819         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3820         rasterParams.gray_spans = callback;
3821         rasterParams.skip_spans = rendered_spans;
3822         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3823
3824         // Out of memory, reallocate some more and try again...
3825         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3826             int new_size = rasterPoolSize * 2;
3827             if (new_size > 1024 * 1024) {
3828                 qWarning("QPainter: Rasterization of primitive failed");
3829                 break;
3830             }
3831
3832             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3833
3834 #if defined(Q_WS_WIN64)
3835             _aligned_free(rasterPoolBase);
3836 #else
3837             if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3838                 free(rasterPoolBase);
3839 #endif
3840
3841             rasterPoolSize = new_size;
3842             rasterPoolBase =
3843 #if defined(Q_WS_WIN64)
3844                 // We make use of setjmp and longjmp in qgrayraster.c which requires
3845                 // 16-byte alignment, hence we hardcode this requirement here..
3846                 (unsigned char *) _aligned_malloc(rasterPoolSize, sizeof(void*) * 2);
3847 #else
3848                 (unsigned char *) malloc(rasterPoolSize);
3849 #endif
3850             Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3851
3852             qt_ft_grays_raster.raster_done(*grayRaster.data());
3853             qt_ft_grays_raster.raster_new(grayRaster.data());
3854             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3855         } else {
3856             done = true;
3857         }
3858     }
3859
3860 #if defined(Q_WS_WIN64)
3861     _aligned_free(rasterPoolBase);
3862 #else
3863     if (rasterPoolBase != rasterPoolOnStack) // initially on the stack
3864         free(rasterPoolBase);
3865 #endif
3866 }
3867
3868 void QRasterPaintEnginePrivate::recalculateFastImages()
3869 {
3870     Q_Q(QRasterPaintEngine);
3871     QRasterPaintEngineState *s = q->state();
3872
3873     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3874                            && s->matrix.type() <= QTransform::TxShear;
3875 }
3876
3877 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3878 {
3879     Q_Q(const QRasterPaintEngine);
3880     const QRasterPaintEngineState *s = q->state();
3881
3882     return s->flags.fast_images
3883            && (mode == QPainter::CompositionMode_SourceOver
3884                || (mode == QPainter::CompositionMode_Source
3885                    && !image.hasAlphaChannel()));
3886 }
3887
3888 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3889 {
3890     Q_ASSERT(image.depth() == 1);
3891
3892     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3893     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3894
3895     QRgb fg = PREMUL(color.rgba());
3896     QRgb bg = 0;
3897
3898     int height = sourceImage.height();
3899     int width = sourceImage.width();
3900     for (int y=0; y<height; ++y) {
3901         uchar *source = sourceImage.scanLine(y);
3902         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3903         if (!source || !target)
3904             QT_THROW(std::bad_alloc()); // we must have run out of memory
3905         for (int x=0; x < width; ++x)
3906             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3907     }
3908     return dest;
3909 }
3910
3911 QRasterBuffer::~QRasterBuffer()
3912 {
3913 }
3914
3915 void QRasterBuffer::init()
3916 {
3917     compositionMode = QPainter::CompositionMode_SourceOver;
3918     monoDestinationWithClut = false;
3919     destColor0 = 0;
3920     destColor1 = 0;
3921 }
3922
3923 QImage::Format QRasterBuffer::prepare(QImage *image)
3924 {
3925     m_buffer = (uchar *)image->bits();
3926     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3927     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3928     bytes_per_pixel = image->depth()/8;
3929     bytes_per_line = image->bytesPerLine();
3930
3931     format = image->format();
3932     drawHelper = qDrawHelper + format;
3933     if (image->depth() == 1 && image->colorTable().size() == 2) {
3934         monoDestinationWithClut = true;
3935         destColor0 = PREMUL(image->colorTable()[0]);
3936         destColor1 = PREMUL(image->colorTable()[1]);
3937     }
3938
3939     return format;
3940 }
3941
3942 void QRasterBuffer::resetBuffer(int val)
3943 {
3944     memset(m_buffer, val, m_height*bytes_per_line);
3945 }
3946
3947
3948 #if defined(Q_WS_QWS)
3949 void QRasterBuffer::prepare(QCustomRasterPaintDevice *device)
3950 {
3951     m_buffer = reinterpret_cast<uchar*>(device->memory());
3952     m_width = qMin(QT_RASTER_COORD_LIMIT, device->width());
3953     m_height = qMin(QT_RASTER_COORD_LIMIT, device->height());
3954     bytes_per_pixel = device->depth() / 8;
3955     bytes_per_line = device->bytesPerLine();
3956     format = device->format();
3957 #ifndef QT_NO_RASTERCALLBACKS
3958     if (!m_buffer)
3959         drawHelper = qDrawHelperCallback + format;
3960     else
3961 #endif
3962         drawHelper = qDrawHelper + format;
3963 }
3964
3965 int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const
3966 {
3967     switch (m) {
3968     case PdmWidth:
3969         return widget->frameGeometry().width();
3970     case PdmHeight:
3971         return widget->frameGeometry().height();
3972     default:
3973         break;
3974     }
3975
3976     return qt_paint_device_metric(widget, m);
3977 }
3978
3979 int QCustomRasterPaintDevice::bytesPerLine() const
3980 {
3981     return (width() * depth() + 7) / 8;
3982 }
3983
3984 #elif defined(Q_OS_SYMBIAN)
3985
3986 void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
3987 {
3988 }
3989
3990 #endif // Q_OS_SYMBIAN
3991
3992 /*!
3993     \class QCustomRasterPaintDevice
3994     \preliminary
3995     \ingroup qws
3996     \since 4.2
3997
3998     \brief The QCustomRasterPaintDevice class is provided to activate
3999     hardware accelerated paint engines in Qt for Embedded Linux.
4000
4001     Note that this class is only available in \l{Qt for Embedded Linux}.
4002
4003     In \l{Qt for Embedded Linux}, painting is a pure software
4004     implementation. But starting with Qt 4.2, it is
4005     possible to add an accelerated graphics driver to take advantage
4006     of available hardware resources.
4007
4008     Hardware acceleration is accomplished by creating a custom screen
4009     driver, accelerating the copying from memory to the screen, and
4010     implementing a custom paint engine accelerating the various
4011     painting operations. Then a custom paint device (derived from the
4012     QCustomRasterPaintDevice class) and a custom window surface
4013     (derived from QWSWindowSurface) must be implemented to make
4014     \l{Qt for Embedded Linux} aware of the accelerated driver.
4015
4016     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
4017     documentation for details.
4018
4019     \sa QRasterPaintEngine, QPaintDevice
4020 */
4021
4022 /*!
4023     \fn QCustomRasterPaintDevice::QCustomRasterPaintDevice(QWidget *widget)
4024
4025     Constructs a custom raster based paint device for the given
4026     top-level \a widget.
4027 */
4028
4029 /*!
4030     \fn int QCustomRasterPaintDevice::bytesPerLine() const
4031
4032     Returns the number of bytes per line in the framebuffer. Note that
4033     this number might be larger than the framebuffer width.
4034 */
4035
4036 /*!
4037     \fn int QCustomRasterPaintDevice::devType() const
4038     \internal
4039 */
4040
4041 /*!
4042     \fn QImage::Format QCustomRasterPaintDevice::format() const
4043
4044     Returns the format of the device's memory buffet.
4045
4046     The default format is QImage::Format_ARGB32_Premultiplied. The
4047     only other valid format is QImage::Format_RGB16.
4048 */
4049
4050 /*!
4051     \fn void * QCustomRasterPaintDevice::memory () const
4052
4053     Returns a pointer to the paint device's memory buffer, or 0 if no
4054     such buffer exists.
4055 */
4056
4057 /*!
4058     \fn int QCustomRasterPaintDevice::metric ( PaintDeviceMetric m ) const
4059     \reimp
4060 */
4061
4062 /*!
4063     \fn QSize QCustomRasterPaintDevice::size () const
4064     \internal
4065 */
4066
4067
4068 QClipData::QClipData(int height)
4069 {
4070     clipSpanHeight = height;
4071     m_clipLines = 0;
4072
4073     allocated = 0;
4074     m_spans = 0;
4075     xmin = xmax = ymin = ymax = 0;
4076     count = 0;
4077
4078     enabled = true;
4079     hasRectClip = hasRegionClip = false;
4080 }
4081
4082 QClipData::~QClipData()
4083 {
4084     if (m_clipLines)
4085         free(m_clipLines);
4086     if (m_spans)
4087         free(m_spans);
4088 }
4089
4090 void QClipData::initialize()
4091 {
4092     if (m_spans)
4093         return;
4094
4095     if (!m_clipLines)
4096         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4097
4098     Q_CHECK_PTR(m_clipLines);
4099     QT_TRY {
4100         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4101         allocated = clipSpanHeight;
4102         Q_CHECK_PTR(m_spans);
4103
4104         QT_TRY {
4105             if (hasRectClip) {
4106                 int y = 0;
4107                 while (y < ymin) {
4108                     m_clipLines[y].spans = 0;
4109                     m_clipLines[y].count = 0;
4110                     ++y;
4111                 }
4112
4113                 const int len = clipRect.width();
4114                 count = 0;
4115                 while (y < ymax) {
4116                     QSpan *span = m_spans + count;
4117                     span->x = xmin;
4118                     span->len = len;
4119                     span->y = y;
4120                     span->coverage = 255;
4121                     ++count;
4122
4123                     m_clipLines[y].spans = span;
4124                     m_clipLines[y].count = 1;
4125                     ++y;
4126                 }
4127
4128                 while (y < clipSpanHeight) {
4129                     m_clipLines[y].spans = 0;
4130                     m_clipLines[y].count = 0;
4131                     ++y;
4132                 }
4133             } else if (hasRegionClip) {
4134
4135                 const QVector<QRect> rects = clipRegion.rects();
4136                 const int numRects = rects.size();
4137
4138                 { // resize
4139                     const int maxSpans = (ymax - ymin) * numRects;
4140                     if (maxSpans > allocated) {
4141                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4142                         allocated = maxSpans;
4143                     }
4144                 }
4145
4146                 int y = 0;
4147                 int firstInBand = 0;
4148                 count = 0;
4149                 while (firstInBand < numRects) {
4150                     const int currMinY = rects.at(firstInBand).y();
4151                     const int currMaxY = currMinY + rects.at(firstInBand).height();
4152
4153                     while (y < currMinY) {
4154                         m_clipLines[y].spans = 0;
4155                         m_clipLines[y].count = 0;
4156                         ++y;
4157                     }
4158
4159                     int lastInBand = firstInBand;
4160                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4161                         ++lastInBand;
4162
4163                     while (y < currMaxY) {
4164
4165                         m_clipLines[y].spans = m_spans + count;
4166                         m_clipLines[y].count = lastInBand - firstInBand + 1;
4167
4168                         for (int r = firstInBand; r <= lastInBand; ++r) {
4169                             const QRect &currRect = rects.at(r);
4170                             QSpan *span = m_spans + count;
4171                             span->x = currRect.x();
4172                             span->len = currRect.width();
4173                             span->y = y;
4174                             span->coverage = 255;
4175                             ++count;
4176                         }
4177                         ++y;
4178                     }
4179
4180                     firstInBand = lastInBand + 1;
4181                 }
4182
4183                 Q_ASSERT(count <= allocated);
4184
4185                 while (y < clipSpanHeight) {
4186                     m_clipLines[y].spans = 0;
4187                     m_clipLines[y].count = 0;
4188                     ++y;
4189                 }
4190
4191             }
4192         } QT_CATCH(...) {
4193             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4194             m_spans = 0;
4195             QT_RETHROW;
4196         }
4197     } QT_CATCH(...) {
4198         free(m_clipLines); // same for clipLines
4199         m_clipLines = 0;
4200         QT_RETHROW;
4201     }
4202 }
4203
4204 void QClipData::fixup()
4205 {
4206     Q_ASSERT(m_spans);
4207
4208     if (count == 0) {
4209         ymin = ymax = xmin = xmax = 0;
4210         return;
4211     }
4212
4213     int y = -1;
4214     ymin = m_spans[0].y;
4215     ymax = m_spans[count-1].y + 1;
4216     xmin = INT_MAX;
4217     xmax = 0;
4218
4219     const int firstLeft = m_spans[0].x;
4220     const int firstRight = m_spans[0].x + m_spans[0].len;
4221     bool isRect = true;
4222
4223     for (int i = 0; i < count; ++i) {
4224         QT_FT_Span_& span = m_spans[i];
4225
4226         if (span.y != y) {
4227             if (span.y != y + 1 && y != -1)
4228                 isRect = false;
4229             y = span.y;
4230             m_clipLines[y].spans = &span;
4231             m_clipLines[y].count = 1;
4232         } else
4233             ++m_clipLines[y].count;
4234
4235         const int spanLeft = span.x;
4236         const int spanRight = spanLeft + span.len;
4237
4238         if (spanLeft < xmin)
4239             xmin = spanLeft;
4240
4241         if (spanRight > xmax)
4242             xmax = spanRight;
4243
4244         if (spanLeft != firstLeft || spanRight != firstRight)
4245             isRect = false;
4246     }
4247
4248     if (isRect) {
4249         hasRectClip = true;
4250         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4251     }
4252 }
4253
4254 /*
4255     Convert \a rect to clip spans.
4256  */
4257 void QClipData::setClipRect(const QRect &rect)
4258 {
4259     if (hasRectClip && rect == clipRect)
4260         return;
4261
4262 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4263     hasRectClip = true;
4264     hasRegionClip = false;
4265     clipRect = rect;
4266
4267     xmin = rect.x();
4268     xmax = rect.x() + rect.width();
4269     ymin = qMin(rect.y(), clipSpanHeight);
4270     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4271
4272     if (m_spans) {
4273         free(m_spans);
4274         m_spans = 0;
4275     }
4276
4277 //    qDebug() << xmin << xmax << ymin << ymax;
4278 }
4279
4280 /*
4281     Convert \a region to clip spans.
4282  */
4283 void QClipData::setClipRegion(const QRegion &region)
4284 {
4285     if (region.rectCount() == 1) {
4286         setClipRect(region.rects().at(0));
4287         return;
4288     }
4289
4290     hasRegionClip = true;
4291     hasRectClip = false;
4292     clipRegion = region;
4293
4294     { // set bounding rect
4295         const QRect rect = region.boundingRect();
4296         xmin = rect.x();
4297         xmax = rect.x() + rect.width();
4298         ymin = rect.y();
4299         ymax = rect.y() + rect.height();
4300     }
4301
4302     if (m_spans) {
4303         free(m_spans);
4304         m_spans = 0;
4305     }
4306
4307 }
4308
4309 /*!
4310     \internal
4311     spans must be sorted on y
4312 */
4313 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
4314                                        const QSpan *spans, const QSpan *end,
4315                                        QSpan **outSpans, int available)
4316 {
4317     const_cast<QClipData *>(clip)->initialize();
4318
4319     QSpan *out = *outSpans;
4320
4321     const QSpan *clipSpans = clip->m_spans + *currentClip;
4322     const QSpan *clipEnd = clip->m_spans + clip->count;
4323
4324     while (available && spans < end ) {
4325         if (clipSpans >= clipEnd) {
4326             spans = end;
4327             break;
4328         }
4329         if (clipSpans->y > spans->y) {
4330             ++spans;
4331             continue;
4332         }
4333         if (spans->y != clipSpans->y) {
4334             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
4335                 clipSpans = clip->m_clipLines[spans->y].spans;
4336             else
4337                 ++clipSpans;
4338             continue;
4339         }
4340         Q_ASSERT(spans->y == clipSpans->y);
4341
4342         int sx1 = spans->x;
4343         int sx2 = sx1 + spans->len;
4344         int cx1 = clipSpans->x;
4345         int cx2 = cx1 + clipSpans->len;
4346
4347         if (cx1 < sx1 && cx2 < sx1) {
4348             ++clipSpans;
4349             continue;
4350         } else if (sx1 < cx1 && sx2 < cx1) {
4351             ++spans;
4352             continue;
4353         }
4354         int x = qMax(sx1, cx1);
4355         int len = qMin(sx2, cx2) - x;
4356         if (len) {
4357             out->x = qMax(sx1, cx1);
4358             out->len = qMin(sx2, cx2) - out->x;
4359             out->y = spans->y;
4360             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
4361             ++out;
4362             --available;
4363         }
4364         if (sx2 < cx2) {
4365             ++spans;
4366         } else {
4367             ++clipSpans;
4368         }
4369     }
4370
4371     *outSpans = out;
4372     *currentClip = clipSpans - clip->m_spans;
4373     return spans;
4374 }
4375
4376 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
4377 {
4378 //     qDebug() << "qt_span_fill_clipped" << spanCount;
4379     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4380
4381     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4382
4383     const int NSPANS = 256;
4384     QSpan cspans[NSPANS];
4385     int currentClip = 0;
4386     const QSpan *end = spans + spanCount;
4387     while (spans < end) {
4388         QSpan *clipped = cspans;
4389         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
4390 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4391 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4392
4393         if (clipped - cspans)
4394             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4395     }
4396 }
4397
4398 /*
4399     \internal
4400     Clip spans to \a{clip}-rectangle.
4401     Returns number of unclipped spans
4402 */
4403 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4404                               const QRect &clip)
4405 {
4406     const short minx = clip.left();
4407     const short miny = clip.top();
4408     const short maxx = clip.right();
4409     const short maxy = clip.bottom();
4410
4411     int n = 0;
4412     for (int i = 0; i < numSpans; ++i) {
4413         if (spans[i].y > maxy)
4414             break;
4415         if (spans[i].y < miny
4416             || spans[i].x > maxx
4417             || spans[i].x + spans[i].len <= minx) {
4418             continue;
4419         }
4420         if (spans[i].x < minx) {
4421             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4422             spans[n].x = minx;
4423         } else {
4424             spans[n].x = spans[i].x;
4425             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4426         }
4427         if (spans[n].len == 0)
4428             continue;
4429         spans[n].y = spans[i].y;
4430         spans[n].coverage = spans[i].coverage;
4431         ++n;
4432     }
4433     return n;
4434 }
4435
4436
4437 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4438                                   void *userData)
4439 {
4440     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4441     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4442
4443     Q_ASSERT(fillData->clip);
4444     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4445
4446     // hw: check if this const_cast<> is safe!!!
4447     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4448                                fillData->clip->clipRect);
4449     if (count > 0)
4450         fillData->unclipped_blend(count, spans, fillData);
4451 }
4452
4453 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4454 {
4455     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4456
4457 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
4458 //     for (int i = 0; i < qMin(count, 10); ++i) {
4459 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4460 //     }
4461
4462     switch (clipData->operation) {
4463
4464     case Qt::IntersectClip:
4465         {
4466             QClipData *newClip = clipData->newClip;
4467             newClip->initialize();
4468
4469             int currentClip = 0;
4470             const QSpan *end = spans + count;
4471             while (spans < end) {
4472                 QSpan *newspans = newClip->m_spans + newClip->count;
4473                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
4474                                            &newspans, newClip->allocated - newClip->count);
4475                 newClip->count = newspans - newClip->m_spans;
4476                 if (spans < end) {
4477                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4478                     newClip->allocated *= 2;
4479                 }
4480             }
4481         }
4482         break;
4483
4484     case Qt::UniteClip:
4485     case Qt::ReplaceClip:
4486         clipData->newClip->appendSpans(spans, count);
4487         break;
4488     case Qt::NoClip:
4489         break;
4490     }
4491 }
4492
4493 #ifndef QT_NO_DEBUG
4494 QImage QRasterBuffer::bufferImage() const
4495 {
4496     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4497
4498     for (int y = 0; y < m_height; ++y) {
4499         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4500
4501         for (int x=0; x<m_width; ++x) {
4502             uint argb = span[x];
4503             image.setPixel(x, y, argb);
4504         }
4505     }
4506     return image;
4507 }
4508 #endif
4509
4510
4511 void QRasterBuffer::flushToARGBImage(QImage *target) const
4512 {
4513     int w = qMin(m_width, target->width());
4514     int h = qMin(m_height, target->height());
4515
4516     for (int y=0; y<h; ++y) {
4517         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4518         QRgb *dest = (QRgb *) target->scanLine(y);
4519         for (int x=0; x<w; ++x) {
4520             QRgb pixel = sourceLine[x];
4521             int alpha = qAlpha(pixel);
4522             if (!alpha) {
4523                 dest[x] = 0;
4524             } else {
4525                 dest[x] = (alpha << 24)
4526                         | ((255*qRed(pixel)/alpha) << 16)
4527                         | ((255*qGreen(pixel)/alpha) << 8)
4528                         | ((255*qBlue(pixel)/alpha) << 0);
4529             }
4530         }
4531     }
4532 }
4533
4534
4535 class QGradientCache
4536 {
4537     struct CacheInfo
4538     {
4539         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4540             stops(s), opacity(op), interpolationMode(mode) {}
4541         uint buffer[GRADIENT_STOPTABLE_SIZE];
4542         QGradientStops stops;
4543         int opacity;
4544         QGradient::InterpolationMode interpolationMode;
4545     };
4546
4547     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4548
4549 public:
4550     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4551         quint64 hash_val = 0;
4552
4553         QGradientStops stops = gradient.stops();
4554         for (int i = 0; i < stops.size() && i <= 2; i++)
4555             hash_val += stops[i].second.rgba();
4556
4557         QMutexLocker lock(&mutex);
4558         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4559
4560         if (it == cache.constEnd())
4561             return addCacheElement(hash_val, gradient, opacity);
4562         else {
4563             do {
4564                 const CacheInfo &cache_info = it.value();
4565                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4566                     return cache_info.buffer;
4567                 ++it;
4568             } while (it != cache.constEnd() && it.key() == hash_val);
4569             // an exact match for these stops and opacity was not found, create new cache
4570             return addCacheElement(hash_val, gradient, opacity);
4571         }
4572     }
4573
4574     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4575 protected:
4576     inline int maxCacheSize() const { return 60; }
4577     inline void generateGradientColorTable(const QGradient& g,
4578                                            uint *colorTable,
4579                                            int size, int opacity) const;
4580     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4581         if (cache.size() == maxCacheSize()) {
4582             // may remove more than 1, but OK
4583             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4584         }
4585         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4586         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4587         return cache.insert(hash_val, cache_entry).value().buffer;
4588     }
4589
4590     QGradientColorTableHash cache;
4591     QMutex mutex;
4592 };
4593
4594 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4595 {
4596     QGradientStops stops = gradient.stops();
4597     int stopCount = stops.count();
4598     Q_ASSERT(stopCount > 0);
4599
4600     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4601
4602     if (stopCount == 2) {
4603         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4604         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4605
4606         qreal first_stop = stops[0].first;
4607         qreal second_stop = stops[1].first;
4608
4609         if (second_stop < first_stop) {
4610             qSwap(first_color, second_color);
4611             qSwap(first_stop, second_stop);
4612         }
4613
4614         if (colorInterpolation) {
4615             first_color = PREMUL(first_color);
4616             second_color = PREMUL(second_color);
4617         }
4618
4619         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4620         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4621
4622         uint red_first = qRed(first_color) << 16;
4623         uint green_first = qGreen(first_color) << 16;
4624         uint blue_first = qBlue(first_color) << 16;
4625         uint alpha_first = qAlpha(first_color) << 16;
4626
4627         uint red_second = qRed(second_color) << 16;
4628         uint green_second = qGreen(second_color) << 16;
4629         uint blue_second = qBlue(second_color) << 16;
4630         uint alpha_second = qAlpha(second_color) << 16;
4631
4632         int i = 0;
4633         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4634             if (colorInterpolation)
4635                 colorTable[i] = first_color;
4636             else
4637                 colorTable[i] = PREMUL(first_color);
4638         }
4639
4640         if (i < second_index) {
4641             qreal reciprocal = qreal(1) / (second_index - first_index);
4642
4643             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4644             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4645             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4646             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4647
4648             // rounding
4649             red_first += 1 << 15;
4650             green_first += 1 << 15;
4651             blue_first += 1 << 15;
4652             alpha_first += 1 << 15;
4653
4654             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4655                 red_first += red_delta;
4656                 green_first += green_delta;
4657                 blue_first += blue_delta;
4658                 alpha_first += alpha_delta;
4659
4660                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4661                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4662
4663                 if (colorInterpolation)
4664                     colorTable[i] = color;
4665                 else
4666                     colorTable[i] = PREMUL(color);
4667             }
4668         }
4669
4670         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4671             if (colorInterpolation)
4672                 colorTable[i] = second_color;
4673             else
4674                 colorTable[i] = PREMUL(second_color);
4675         }
4676
4677         return;
4678     }
4679
4680     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4681     if (stopCount == 1) {
4682         current_color = PREMUL(current_color);
4683         for (int i = 0; i < size; ++i)
4684             colorTable[i] = current_color;
4685         return;
4686     }
4687
4688     // The position where the gradient begins and ends
4689     qreal begin_pos = stops[0].first;
4690     qreal end_pos = stops[stopCount-1].first;
4691
4692     int pos = 0; // The position in the color table.
4693     uint next_color;
4694
4695     qreal incr = 1 / qreal(size); // the double increment.
4696     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4697
4698      // Up to first point
4699     colorTable[pos++] = PREMUL(current_color);
4700     while (dpos <= begin_pos) {
4701         colorTable[pos] = colorTable[pos - 1];
4702         ++pos;
4703         dpos += incr;
4704     }
4705
4706     int current_stop = 0; // We always interpolate between current and current + 1.
4707
4708     qreal t; // position between current left and right stops
4709     qreal t_delta; // the t increment per entry in the color table
4710
4711     if (dpos < end_pos) {
4712         // Gradient area
4713         while (dpos > stops[current_stop+1].first)
4714             ++current_stop;
4715
4716         if (current_stop != 0)
4717             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4718         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4719
4720         if (colorInterpolation) {
4721             current_color = PREMUL(current_color);
4722             next_color = PREMUL(next_color);
4723         }
4724
4725         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4726         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4727         t = (dpos - stops[current_stop].first) * c;
4728         t_delta = incr * c;
4729
4730         while (true) {
4731             Q_ASSERT(current_stop < stopCount);
4732
4733             int dist = qRound(t);
4734             int idist = 256 - dist;
4735
4736             if (colorInterpolation)
4737                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4738             else
4739                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4740
4741             ++pos;
4742             dpos += incr;
4743
4744             if (dpos >= end_pos)
4745                 break;
4746
4747             t += t_delta;
4748
4749             int skip = 0;
4750             while (dpos > stops[current_stop+skip+1].first)
4751                 ++skip;
4752
4753             if (skip != 0) {
4754                 current_stop += skip;
4755                 if (skip == 1)
4756                     current_color = next_color;
4757                 else
4758                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4759                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4760
4761                 if (colorInterpolation) {
4762                     if (skip != 1)
4763                         current_color = PREMUL(current_color);
4764                     next_color = PREMUL(next_color);
4765                 }
4766
4767                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4768                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4769                 t = (dpos - stops[current_stop].first) * c;
4770                 t_delta = incr * c;
4771             }
4772         }
4773     }
4774
4775     // After last point
4776     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4777     while (pos < size - 1) {
4778         colorTable[pos] = current_color;
4779         ++pos;
4780     }
4781
4782     // Make sure the last color stop is represented at the end of the table
4783     colorTable[size - 1] = current_color;
4784 }
4785
4786 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4787
4788
4789 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4790 {
4791     rasterBuffer = rb;
4792 #ifdef Q_WS_QWS
4793     rasterEngine = const_cast<QRasterPaintEngine *>(pe);
4794 #endif
4795     type = None;
4796     txop = 0;
4797     bilinear = false;
4798     m11 = m22 = m33 = 1.;
4799     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4800     clip = pe ? pe->d_func()->clip() : 0;
4801 }
4802
4803 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4804
4805 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4806 {
4807     Qt::BrushStyle brushStyle = qbrush_style(brush);
4808     switch (brushStyle) {
4809     case Qt::SolidPattern: {
4810         type = Solid;
4811         QColor c = qbrush_color(brush);
4812         QRgb rgba = c.rgba();
4813         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4814         if ((solid.color & 0xff000000) == 0
4815             && compositionMode == QPainter::CompositionMode_SourceOver) {
4816             type = None;
4817         }
4818         break;
4819     }
4820
4821     case Qt::LinearGradientPattern:
4822         {
4823             type = LinearGradient;
4824             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4825             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4826             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4827             gradient.spread = g->spread();
4828
4829             QLinearGradientData &linearData = gradient.linear;
4830
4831             linearData.origin.x = g->start().x();
4832             linearData.origin.y = g->start().y();
4833             linearData.end.x = g->finalStop().x();
4834             linearData.end.y = g->finalStop().y();
4835             break;
4836         }
4837
4838     case Qt::RadialGradientPattern:
4839         {
4840             type = RadialGradient;
4841             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4842             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4843             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4844             gradient.spread = g->spread();
4845
4846             QRadialGradientData &radialData = gradient.radial;
4847
4848             QPointF center = g->center();
4849             radialData.center.x = center.x();
4850             radialData.center.y = center.y();
4851             radialData.center.radius = g->centerRadius();
4852             QPointF focal = g->focalPoint();
4853             radialData.focal.x = focal.x();
4854             radialData.focal.y = focal.y();
4855             radialData.focal.radius = g->focalRadius();
4856         }
4857         break;
4858
4859     case Qt::ConicalGradientPattern:
4860         {
4861             type = ConicalGradient;
4862             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4863             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4864             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4865             gradient.spread = QGradient::RepeatSpread;
4866
4867             QConicalGradientData &conicalData = gradient.conical;
4868
4869             QPointF center = g->center();
4870             conicalData.center.x = center.x();
4871             conicalData.center.y = center.y();
4872             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4873         }
4874         break;
4875
4876     case Qt::Dense1Pattern:
4877     case Qt::Dense2Pattern:
4878     case Qt::Dense3Pattern:
4879     case Qt::Dense4Pattern:
4880     case Qt::Dense5Pattern:
4881     case Qt::Dense6Pattern:
4882     case Qt::Dense7Pattern:
4883     case Qt::HorPattern:
4884     case Qt::VerPattern:
4885     case Qt::CrossPattern:
4886     case Qt::BDiagPattern:
4887     case Qt::FDiagPattern:
4888     case Qt::DiagCrossPattern:
4889         type = Texture;
4890         if (!tempImage)
4891             tempImage = new QImage();
4892         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4893         initTexture(tempImage, alpha, QTextureData::Tiled);
4894         break;
4895     case Qt::TexturePattern:
4896         type = Texture;
4897         if (!tempImage)
4898             tempImage = new QImage();
4899
4900         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4901             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4902         else
4903             *tempImage = brush.textureImage();
4904         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4905         break;
4906
4907     case Qt::NoBrush:
4908     default:
4909         type = None;
4910         break;
4911     }
4912     adjustSpanMethods();
4913 }
4914
4915 void QSpanData::adjustSpanMethods()
4916 {
4917     bitmapBlit = 0;
4918     alphamapBlit = 0;
4919     alphaRGBBlit = 0;
4920
4921     fillRect = 0;
4922
4923     switch(type) {
4924     case None:
4925         unclipped_blend = 0;
4926         break;
4927     case Solid:
4928         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4929         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4930         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4931         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4932         fillRect = rasterBuffer->drawHelper->fillRect;
4933         break;
4934     case LinearGradient:
4935     case RadialGradient:
4936     case ConicalGradient:
4937         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4938         break;
4939     case Texture:
4940 #ifdef Q_WS_QWS
4941 #ifndef QT_NO_RASTERCALLBACKS
4942         if (!rasterBuffer->buffer())
4943             unclipped_blend = qBlendTextureCallback;
4944         else
4945 #endif
4946             unclipped_blend = qBlendTexture;
4947 #else
4948         unclipped_blend = qBlendTexture;
4949 #endif
4950         if (!texture.imageData)
4951             unclipped_blend = 0;
4952
4953         break;
4954     }
4955     // setup clipping
4956     if (!unclipped_blend) {
4957         blend = 0;
4958     } else if (!clip) {
4959         blend = unclipped_blend;
4960     } else if (clip->hasRectClip) {
4961         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4962     } else {
4963         blend = qt_span_fill_clipped;
4964     }
4965 }
4966
4967 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4968 {
4969     QTransform delta;
4970     // make sure we round off correctly in qdrawhelper.cpp
4971     delta.translate(1.0 / 65536, 1.0 / 65536);
4972
4973     QTransform inv = (delta * matrix).inverted();
4974     m11 = inv.m11();
4975     m12 = inv.m12();
4976     m13 = inv.m13();
4977     m21 = inv.m21();
4978     m22 = inv.m22();
4979     m23 = inv.m23();
4980     m33 = inv.m33();
4981     dx = inv.dx();
4982     dy = inv.dy();
4983     txop = inv.type();
4984     bilinear = bilin;
4985
4986     const bool affine = !m13 && !m23;
4987     fast_matrix = affine
4988         && m11 * m11 + m21 * m21 < 1e4
4989         && m12 * m12 + m22 * m22 < 1e4
4990         && qAbs(dx) < 1e4
4991         && qAbs(dy) < 1e4;
4992
4993     adjustSpanMethods();
4994 }
4995
4996 extern const QVector<QRgb> *qt_image_colortable(const QImage &image);
4997
4998 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4999 {
5000     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
5001     if (!d || d->height == 0) {
5002         texture.imageData = 0;
5003         texture.width = 0;
5004         texture.height = 0;
5005         texture.x1 = 0;
5006         texture.y1 = 0;
5007         texture.x2 = 0;
5008         texture.y2 = 0;
5009         texture.bytesPerLine = 0;
5010         texture.format = QImage::Format_Invalid;
5011         texture.colorTable = 0;
5012         texture.hasAlpha = alpha != 256;
5013     } else {
5014         texture.imageData = d->data;
5015         texture.width = d->width;
5016         texture.height = d->height;
5017
5018         if (sourceRect.isNull()) {
5019             texture.x1 = 0;
5020             texture.y1 = 0;
5021             texture.x2 = texture.width;
5022             texture.y2 = texture.height;
5023         } else {
5024             texture.x1 = sourceRect.x();
5025             texture.y1 = sourceRect.y();
5026             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
5027             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
5028         }
5029
5030         texture.bytesPerLine = d->bytes_per_line;
5031
5032         texture.format = d->format;
5033         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
5034         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
5035     }
5036     texture.const_alpha = alpha;
5037     texture.type = _type;
5038
5039     adjustSpanMethods();
5040 }
5041
5042 /*!
5043     \internal
5044     \a x and \a y is relative to the midpoint of \a rect.
5045 */
5046 static inline void drawEllipsePoints(int x, int y, int length,
5047                                      const QRect &rect,
5048                                      const QRect &clip,
5049                                      ProcessSpans pen_func, ProcessSpans brush_func,
5050                                      QSpanData *pen_data, QSpanData *brush_data)
5051 {
5052     if (length == 0)
5053         return;
5054
5055     QT_FT_Span outline[4];
5056     const int midx = rect.x() + (rect.width() + 1) / 2;
5057     const int midy = rect.y() + (rect.height() + 1) / 2;
5058
5059     x = x + midx;
5060     y = midy - y;
5061
5062     // topleft
5063     outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
5064     outline[0].len = qMin(length, x - outline[0].x);
5065     outline[0].y = y;
5066     outline[0].coverage = 255;
5067
5068     // topright
5069     outline[1].x = x;
5070     outline[1].len = length;
5071     outline[1].y = y;
5072     outline[1].coverage = 255;
5073
5074     // bottomleft
5075     outline[2].x = outline[0].x;
5076     outline[2].len = outline[0].len;
5077     outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
5078     outline[2].coverage = 255;
5079
5080     // bottomright
5081     outline[3].x = x;
5082     outline[3].len = length;
5083     outline[3].y = outline[2].y;
5084     outline[3].coverage = 255;
5085
5086     if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
5087         QT_FT_Span fill[2];
5088
5089         // top fill
5090         fill[0].x = outline[0].x + outline[0].len - 1;
5091         fill[0].len = qMax(0, outline[1].x - fill[0].x);
5092         fill[0].y = outline[1].y;
5093         fill[0].coverage = 255;
5094
5095         // bottom fill
5096         fill[1].x = outline[2].x + outline[2].len - 1;
5097         fill[1].len = qMax(0, outline[3].x - fill[1].x);
5098         fill[1].y = outline[3].y;
5099         fill[1].coverage = 255;
5100
5101         int n = (fill[0].y >= fill[1].y ? 1 : 2);
5102         n = qt_intersect_spans(fill, n, clip);
5103         if (n > 0)
5104             brush_func(n, fill, brush_data);
5105     }
5106     if (pen_func) {
5107         int n = (outline[1].y >= outline[2].y ? 2 : 4);
5108         n = qt_intersect_spans(outline, n, clip);
5109         if (n > 0)
5110             pen_func(n, outline, pen_data);
5111     }
5112 }
5113
5114 /*!
5115     \internal
5116     Draws an ellipse using the integer point midpoint algorithm.
5117 */
5118 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
5119                                    ProcessSpans pen_func, ProcessSpans brush_func,
5120                                    QSpanData *pen_data, QSpanData *brush_data)
5121 {
5122     const qreal a = qreal(rect.width()) / 2;
5123     const qreal b = qreal(rect.height()) / 2;
5124     qreal d = b*b - (a*a*b) + 0.25*a*a;
5125
5126     int x = 0;
5127     int y = (rect.height() + 1) / 2;
5128     int startx = x;
5129
5130     // region 1
5131     while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
5132         if (d < 0) { // select E
5133             d += b*b*(2*x + 3);
5134             ++x;
5135         } else {     // select SE
5136             d += b*b*(2*x + 3) + a*a*(-2*y + 2);
5137             drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
5138                               pen_func, brush_func, pen_data, brush_data);
5139             startx = ++x;
5140             --y;
5141         }
5142     }
5143     drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
5144                       pen_func, brush_func, pen_data, brush_data);
5145
5146     // region 2
5147     d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
5148     const int miny = rect.height() & 0x1;
5149     while (y > miny) {
5150         if (d < 0) { // select SE
5151             d += b*b*(2*x + 2) + a*a*(-2*y + 3);
5152             ++x;
5153         } else {     // select S
5154             d += a*a*(-2*y + 3);
5155         }
5156         --y;
5157         drawEllipsePoints(x, y, 1, rect, clip,
5158                           pen_func, brush_func, pen_data, brush_data);
5159     }
5160 }
5161
5162 /*!
5163     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
5164     \overload
5165
5166     Draws the first \a pointCount points in the buffer \a points
5167
5168     The default implementation converts the first \a pointCount QPoints in \a points
5169     to QPointFs and calls the floating point version of drawPoints.
5170 */
5171
5172 /*!
5173     \fn void QRasterPaintEngine::drawEllipse(const QRect &rect)
5174     \overload
5175
5176     Reimplement this function to draw the largest ellipse that can be
5177     contained within rectangle \a rect.
5178 */
5179
5180 #ifdef QT_DEBUG_DRAW
5181 void dumpClip(int width, int height, const QClipData *clip)
5182 {
5183     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
5184     clipImg.fill(0xffff0000);
5185
5186     int x0 = width;
5187     int x1 = 0;
5188     int y0 = height;
5189     int y1 = 0;
5190
5191     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
5192
5193     for (int i = 0; i < clip->count; ++i) {
5194         const QSpan *span = ((QClipData *) clip)->spans() + i;
5195         for (int j = 0; j < span->len; ++j)
5196             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
5197         x0 = qMin(x0, int(span->x));
5198         x1 = qMax(x1, int(span->x + span->len - 1));
5199
5200         y0 = qMin(y0, int(span->y));
5201         y1 = qMax(y1, int(span->y));
5202     }
5203
5204     static int counter = 0;
5205
5206     Q_ASSERT(y0 >= 0);
5207     Q_ASSERT(x0 >= 0);
5208     Q_ASSERT(y1 >= 0);
5209     Q_ASSERT(x1 >= 0);
5210
5211     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
5212     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
5213 }
5214 #endif
5215
5216
5217 QT_END_NAMESPACE