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