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