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