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