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