2841a583d537326c87a16385a4a63d827f48c039
[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                         qRound(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 uchar *bits = image.bits();
2822         for (int i=0; i<numGlyphs; ++i) {
2823
2824             QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
2825             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2826             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2827             if (c.isNull())
2828                 continue;
2829
2830             int x = qFloor(positions[i].x) + c.baseLineX - margin;
2831             int y = qRound(positions[i].y) - c.baseLineY - margin;
2832
2833             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2834             //        c.x, c.y,
2835             //        c.w, c.h,
2836             //        c.baseLineX, c.baseLineY,
2837             //        glyphs[i],
2838             //        x, y,
2839             //        positions[i].x.toInt(), positions[i].y.toInt());
2840
2841             alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2842         }
2843     }
2844     return true;
2845 }
2846
2847
2848 /*!
2849  * Returns true if the rectangle is completely within the current clip
2850  * state of the paint engine.
2851  */
2852 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2853 {
2854     const QClipData *cl = clip();
2855     if (!cl) {
2856         // inline contains() for performance (we know the rects are normalized)
2857         const QRect &r1 = deviceRect;
2858         return (r.left() >= r1.left() && r.right() <= r1.right()
2859                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2860     }
2861
2862
2863     if (cl->hasRectClip) {
2864         // currently all painting functions clips to deviceRect internally
2865         if (cl->clipRect == deviceRect)
2866             return true;
2867
2868         // inline contains() for performance (we know the rects are normalized)
2869         const QRect &r1 = cl->clipRect;
2870         return (r.left() >= r1.left() && r.right() <= r1.right()
2871                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2872     } else {
2873         return qt_region_strictContains(cl->clipRegion, r);
2874     }
2875 }
2876
2877 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2878                                             int penWidth) const
2879 {
2880     Q_Q(const QRasterPaintEngine);
2881     const QRasterPaintEngineState *s = q->state();
2882     const QClipData *cl = clip();
2883     if (!cl) {
2884         QRect r = rect.normalized();
2885         // inline contains() for performance (we know the rects are normalized)
2886         const QRect &r1 = deviceRect;
2887         return (r.left() >= r1.left() && r.right() <= r1.right()
2888                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2889     }
2890
2891
2892     // currently all painting functions that call this function clip to deviceRect internally
2893     if (cl->hasRectClip && cl->clipRect == deviceRect)
2894         return true;
2895
2896     if (s->flags.antialiased)
2897         ++penWidth;
2898
2899     QRect r = rect.normalized();
2900     if (penWidth > 0) {
2901         r.setX(r.x() - penWidth);
2902         r.setY(r.y() - penWidth);
2903         r.setWidth(r.width() + 2 * penWidth);
2904         r.setHeight(r.height() + 2 * penWidth);
2905     }
2906
2907     if (cl->hasRectClip) {
2908         // inline contains() for performance (we know the rects are normalized)
2909         const QRect &r1 = cl->clipRect;
2910         return (r.left() >= r1.left() && r.right() <= r1.right()
2911                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2912     } else {
2913         return qt_region_strictContains(cl->clipRegion, r);
2914     }
2915 }
2916
2917 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
2918                                                    int penWidth) const
2919 {
2920     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
2921 }
2922
2923 inline ProcessSpans
2924 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
2925                                         const QSpanData *data) const
2926 {
2927     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2928 }
2929
2930 inline ProcessSpans
2931 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
2932                                         const QSpanData *data) const
2933 {
2934     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2935 }
2936
2937 inline ProcessSpans
2938 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
2939                                       const QSpanData *data) const
2940 {
2941     Q_Q(const QRasterPaintEngine);
2942     const QRasterPaintEngineState *s = q->state();
2943
2944     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
2945         return data->blend;
2946     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
2947     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
2948 }
2949
2950 static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
2951                                          glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
2952 {
2953     QFixed clipLeft = QFixed::fromReal(clip.left());
2954     QFixed clipRight = QFixed::fromReal(clip.right());
2955     QFixed clipTop = QFixed::fromReal(clip.top());
2956     QFixed clipBottom = QFixed::fromReal(clip.bottom());
2957
2958     int first = 0;
2959     while (first < numGlyphs) {
2960         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
2961         QFixed left = metrics.x + positions[first].x;
2962         QFixed top = metrics.y + positions[first].y;
2963         QFixed right = left + metrics.width;
2964         QFixed bottom = top + metrics.height;
2965         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2966             break;
2967         ++first;
2968     }
2969     int last = numGlyphs - 1;
2970     while (last > first) {
2971         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
2972         QFixed left = metrics.x + positions[last].x;
2973         QFixed top = metrics.y + positions[last].y;
2974         QFixed right = left + metrics.width;
2975         QFixed bottom = top + metrics.height;
2976         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2977             break;
2978         --last;
2979     }
2980     return QPair<int, int>(first, last + 1);
2981 }
2982
2983 /*!
2984    \reimp
2985 */
2986 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
2987 {
2988     if (textItem->numGlyphs == 0)
2989         return;
2990
2991     ensurePen();
2992     ensureRasterState();
2993
2994     QFontEngine *fontEngine = textItem->fontEngine();
2995     if (!supportsTransformations(fontEngine)) {
2996         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
2997                          fontEngine);
2998     } else if (state()->matrix.type() < QTransform::TxProject) {
2999         bool invertible;
3000         QTransform invMat = state()->matrix.inverted(&invertible);
3001         if (!invertible)
3002             return;
3003
3004         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3005                                                   textItem->fontEngine(), textItem->glyphs,
3006                                                   textItem->glyphPositions, textItem->numGlyphs);
3007         QStaticTextItem copy = *textItem;
3008         copy.glyphs += range.first;
3009         copy.glyphPositions += range.first;
3010         copy.numGlyphs = range.second - range.first;
3011         QPaintEngineEx::drawStaticTextItem(&copy);
3012     } else {
3013         QPaintEngineEx::drawStaticTextItem(textItem);
3014     }
3015 }
3016
3017 /*!
3018     \reimp
3019 */
3020 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3021 {
3022     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3023
3024 #ifdef QT_DEBUG_DRAW
3025     Q_D(QRasterPaintEngine);
3026     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3027            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3028            d->glyphCacheType);
3029 #endif
3030
3031     if (ti.glyphs.numGlyphs == 0)
3032         return;
3033     ensurePen();
3034     ensureRasterState();
3035
3036     QRasterPaintEngineState *s = state();
3037     QTransform matrix = s->matrix;
3038
3039     if (!supportsTransformations(ti.fontEngine)) {
3040         QVarLengthArray<QFixedPoint> positions;
3041         QVarLengthArray<glyph_t> glyphs;
3042
3043         matrix.translate(p.x(), p.y());
3044         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3045
3046         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3047     } else if (matrix.type() < QTransform::TxProject) {
3048         bool invertible;
3049         QTransform invMat = matrix.inverted(&invertible);
3050         if (!invertible)
3051             return;
3052
3053         QVarLengthArray<QFixedPoint> positions;
3054         QVarLengthArray<glyph_t> glyphs;
3055
3056         ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
3057                                          ti.flags, glyphs, positions);
3058         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3059                                                   ti.fontEngine, glyphs.data(), positions.data(),
3060                                                   glyphs.size());
3061
3062         if (range.first >= range.second)
3063             return;
3064
3065         QStaticTextItem staticTextItem;
3066         staticTextItem.color = s->pen.color();
3067         staticTextItem.font = s->font;
3068         staticTextItem.setFontEngine(ti.fontEngine);
3069         staticTextItem.numGlyphs = range.second - range.first;
3070         staticTextItem.glyphs = glyphs.data() + range.first;
3071         staticTextItem.glyphPositions = positions.data() + range.first;
3072         QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3073     } else {
3074         QPaintEngineEx::drawTextItem(p, ti);
3075     }
3076 }
3077
3078 /*!
3079     \reimp
3080 */
3081 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3082 {
3083     Q_D(QRasterPaintEngine);
3084     QRasterPaintEngineState *s = state();
3085
3086     ensurePen();
3087     if (!s->penData.blend)
3088         return;
3089
3090     if (!s->flags.fast_pen) {
3091         QPaintEngineEx::drawPoints(points, pointCount);
3092         return;
3093     }
3094
3095     QCosmeticStroker stroker(s, d->deviceRect);
3096     stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3097     stroker.drawPoints(points, pointCount);
3098 }
3099
3100
3101 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3102 {
3103     Q_D(QRasterPaintEngine);
3104     QRasterPaintEngineState *s = state();
3105
3106     ensurePen();
3107     if (!s->penData.blend)
3108         return;
3109
3110     if (!s->flags.fast_pen) {
3111         QPaintEngineEx::drawPoints(points, pointCount);
3112         return;
3113     }
3114
3115     QCosmeticStroker stroker(s, d->deviceRect);
3116     stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3117     stroker.drawPoints(points, pointCount);
3118 }
3119
3120 /*!
3121     \reimp
3122 */
3123 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3124 {
3125 #ifdef QT_DEBUG_DRAW
3126     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3127 #endif
3128     Q_D(QRasterPaintEngine);
3129     QRasterPaintEngineState *s = state();
3130
3131     ensurePen();
3132     if (!s->penData.blend)
3133         return;
3134
3135     if (s->flags.fast_pen) {
3136         QCosmeticStroker stroker(s, d->deviceRect);
3137         stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3138         for (int i=0; i<lineCount; ++i) {
3139             const QLine &l = lines[i];
3140             stroker.drawLine(l.p1(), l.p2());
3141         }
3142     } else {
3143         QPaintEngineEx::drawLines(lines, lineCount);
3144     }
3145 }
3146
3147 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3148                                                      qreal width,
3149                                                      int *dashIndex,
3150                                                      qreal *dashOffset,
3151                                                      bool *inDash)
3152 {
3153     Q_Q(QRasterPaintEngine);
3154     QRasterPaintEngineState *s = q->state();
3155
3156     const QPen &pen = s->lastPen;
3157     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3158     const QVector<qreal> pattern = pen.dashPattern();
3159
3160     qreal patternLength = 0;
3161     for (int i = 0; i < pattern.size(); ++i)
3162         patternLength += pattern.at(i);
3163
3164     if (patternLength <= 0)
3165         return;
3166
3167     qreal length = line.length();
3168     Q_ASSERT(length > 0);
3169     while (length > 0) {
3170         const bool rasterize = *inDash;
3171         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3172         QLineF l = line;
3173
3174         if (dash >= length) {
3175             dash = length;
3176             *dashOffset += dash / width;
3177             length = 0;
3178         } else {
3179             *dashOffset = 0;
3180             *inDash = !(*inDash);
3181             if (++*dashIndex >= pattern.size())
3182                 *dashIndex = 0;
3183             length -= dash;
3184             l.setLength(dash);
3185             line.setP1(l.p2());
3186         }
3187
3188         if (rasterize && dash > 0)
3189             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3190     }
3191 }
3192
3193 /*!
3194     \reimp
3195 */
3196 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3197 {
3198 #ifdef QT_DEBUG_DRAW
3199     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3200 #endif
3201     Q_D(QRasterPaintEngine);
3202     QRasterPaintEngineState *s = state();
3203
3204     ensurePen();
3205     if (!s->penData.blend)
3206         return;
3207     if (s->flags.fast_pen) {
3208         QCosmeticStroker stroker(s, d->deviceRect);
3209         stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3210         for (int i=0; i<lineCount; ++i) {
3211             QLineF line = lines[i];
3212             stroker.drawLine(line.p1(), line.p2());
3213         }
3214     } else {
3215         QPaintEngineEx::drawLines(lines, lineCount);
3216     }
3217 }
3218
3219
3220 /*!
3221     \reimp
3222 */
3223 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3224 {
3225     Q_D(QRasterPaintEngine);
3226     QRasterPaintEngineState *s = state();
3227
3228     ensurePen();
3229     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3230            || (qpen_style(s->lastPen) == Qt::NoPen))
3231         && !s->flags.antialiased
3232         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3233         && !rect.isEmpty()
3234         && s->matrix.type() <= QTransform::TxScale) // no shear
3235     {
3236         ensureBrush();
3237         const QRectF r = s->matrix.mapRect(rect);
3238         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3239         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3240         const QRect brect = QRect(int(r.x()), int(r.y()),
3241                                   int_dim(r.x(), r.width()),
3242                                   int_dim(r.y(), r.height()));
3243         if (brect == r) {
3244             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3245                                    &s->penData, &s->brushData);
3246             return;
3247         }
3248     }
3249     QPaintEngineEx::drawEllipse(rect);
3250 }
3251
3252
3253 #ifdef Q_OS_WIN
3254 /*!
3255     \internal
3256 */
3257 void QRasterPaintEngine::setDC(HDC hdc) {
3258     Q_D(QRasterPaintEngine);
3259     d->hdc = hdc;
3260 }
3261
3262 /*!
3263     \internal
3264 */
3265 HDC QRasterPaintEngine::getDC() const
3266 {
3267     Q_D(const QRasterPaintEngine);
3268     return d->hdc;
3269 }
3270
3271 /*!
3272     \internal
3273 */
3274 void QRasterPaintEngine::releaseDC(HDC) const
3275 {
3276 }
3277
3278 #endif
3279
3280 /*!
3281     \internal
3282 */
3283 bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const
3284 {
3285     const QTransform &m = state()->matrix;
3286     return supportsTransformations(fontEngine, m);
3287 }
3288
3289 /*!
3290     \internal
3291 */
3292 bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const
3293 {
3294     if (fontEngine->supportsTransformations(m))
3295         return true;
3296
3297     return !shouldDrawCachedGlyphs(fontEngine, m);
3298 }
3299
3300 /*!
3301     \internal
3302 */
3303 QPoint QRasterPaintEngine::coordinateOffset() const
3304 {
3305     return QPoint(0, 0);
3306 }
3307
3308 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3309 {
3310     Q_ASSERT(fg);
3311     if (!fg->blend)
3312         return;
3313     Q_D(QRasterPaintEngine);
3314
3315     Q_ASSERT(image.depth() == 1);
3316
3317     const int spanCount = 256;
3318     QT_FT_Span spans[spanCount];
3319     int n = 0;
3320
3321     // Boundaries
3322     int w = image.width();
3323     int h = image.height();
3324     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3325     int ymin = qMax(qRound(pos.y()), 0);
3326     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3327     int xmin = qMax(qRound(pos.x()), 0);
3328
3329     int x_offset = xmin - qRound(pos.x());
3330
3331     QImage::Format format = image.format();
3332     for (int y = ymin; y < ymax; ++y) {
3333         const uchar *src = image.scanLine(y - qRound(pos.y()));
3334         if (format == QImage::Format_MonoLSB) {
3335             for (int x = 0; x < xmax - xmin; ++x) {
3336                 int src_x = x + x_offset;
3337                 uchar pixel = src[src_x >> 3];
3338                 if (!pixel) {
3339                     x += 7 - (src_x%8);
3340                     continue;
3341                 }
3342                 if (pixel & (0x1 << (src_x & 7))) {
3343                     spans[n].x = xmin + x;
3344                     spans[n].y = y;
3345                     spans[n].coverage = 255;
3346                     int len = 1;
3347                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3348                         ++src_x;
3349                         ++len;
3350                     }
3351                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3352                     x += len;
3353                     ++n;
3354                     if (n == spanCount) {
3355                         fg->blend(n, spans, fg);
3356                         n = 0;
3357                     }
3358                 }
3359             }
3360         } else {
3361             for (int x = 0; x < xmax - xmin; ++x) {
3362                 int src_x = x + x_offset;
3363                 uchar pixel = src[src_x >> 3];
3364                 if (!pixel) {
3365                     x += 7 - (src_x%8);
3366                     continue;
3367                 }
3368                 if (pixel & (0x80 >> (x & 7))) {
3369                     spans[n].x = xmin + x;
3370                     spans[n].y = y;
3371                     spans[n].coverage = 255;
3372                     int len = 1;
3373                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3374                         ++src_x;
3375                         ++len;
3376                     }
3377                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3378                     x += len;
3379                     ++n;
3380                     if (n == spanCount) {
3381                         fg->blend(n, spans, fg);
3382                         n = 0;
3383                     }
3384                 }
3385             }
3386         }
3387     }
3388     if (n) {
3389         fg->blend(n, spans, fg);
3390         n = 0;
3391     }
3392 }
3393
3394 /*!
3395     \enum QRasterPaintEngine::ClipType
3396     \internal
3397
3398     \value RectClip Indicates that the currently set clip is a single rectangle.
3399     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3400 */
3401
3402 /*!
3403     \internal
3404     Returns the type of the clip currently set.
3405 */
3406 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3407 {
3408     Q_D(const QRasterPaintEngine);
3409
3410     const QClipData *clip = d->clip();
3411     if (!clip || clip->hasRectClip)
3412         return RectClip;
3413     else
3414         return ComplexClip;
3415 }
3416
3417 /*!
3418     \internal
3419     Returns the bounding rect of the currently set clip.
3420 */
3421 QRect QRasterPaintEngine::clipBoundingRect() const
3422 {
3423     Q_D(const QRasterPaintEngine);
3424
3425     const QClipData *clip = d->clip();
3426
3427     if (!clip)
3428         return d->deviceRect;
3429
3430     if (clip->hasRectClip)
3431         return clip->clipRect;
3432
3433     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3434 }
3435
3436 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3437 {
3438     Q_Q(QRasterPaintEngine);
3439     QRasterPaintEngineState *s = q->state();
3440
3441     rasterizer->setAntialiased(s->flags.antialiased);
3442     rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
3443
3444     QRect clipRect(deviceRect);
3445     ProcessSpans blend;
3446     // ### get from optimized rectbased QClipData
3447
3448     const QClipData *c = clip();
3449     if (c) {
3450         const QRect r(QPoint(c->xmin, c->ymin),
3451                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3452         clipRect = clipRect.intersected(r);
3453         blend = data->blend;
3454     } else {
3455         blend = data->unclipped_blend;
3456     }
3457
3458     rasterizer->setClipRect(clipRect);
3459     rasterizer->initialize(blend, data);
3460 }
3461
3462 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3463                                           ProcessSpans callback,
3464                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3465 {
3466     if (!callback || !outline)
3467         return;
3468
3469     Q_Q(QRasterPaintEngine);
3470     QRasterPaintEngineState *s = q->state();
3471
3472     if (!s->flags.antialiased) {
3473         initializeRasterizer(spanData);
3474
3475         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3476                                       ? Qt::WindingFill
3477                                       : Qt::OddEvenFill;
3478
3479         rasterizer->rasterize(outline, fillRule);
3480         return;
3481     }
3482
3483     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3484 }
3485
3486 extern "C" {
3487     int q_gray_rendered_spans(QT_FT_Raster raster);
3488 }
3489
3490 static inline uchar *alignAddress(uchar *address, quintptr alignmentMask)
3491 {
3492     return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
3493 }
3494
3495 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3496                                           ProcessSpans callback,
3497                                           void *userData, QRasterBuffer *)
3498 {
3499     if (!callback || !outline)
3500         return;
3501
3502     Q_Q(QRasterPaintEngine);
3503     QRasterPaintEngineState *s = q->state();
3504
3505     if (!s->flags.antialiased) {
3506         rasterizer->setAntialiased(s->flags.antialiased);
3507         rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
3508         rasterizer->setClipRect(deviceRect);
3509         rasterizer->initialize(callback, userData);
3510
3511         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3512                                       ? Qt::WindingFill
3513                                       : Qt::OddEvenFill;
3514
3515         rasterizer->rasterize(outline, fillRule);
3516         return;
3517     }
3518
3519     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3520     // minimize memory reallocations. However if initial size for
3521     // raster pool is changed for lower value, reallocations will
3522     // occur normally.
3523     int rasterPoolSize = MINIMUM_POOL_SIZE;
3524     uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
3525     uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
3526     uchar *rasterPoolOnHeap = 0;
3527
3528     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3529
3530     void *data = userData;
3531
3532     QT_FT_BBox clip_box = { deviceRect.x(),
3533                             deviceRect.y(),
3534                             deviceRect.x() + deviceRect.width(),
3535                             deviceRect.y() + deviceRect.height() };
3536
3537     QT_FT_Raster_Params rasterParams;
3538     rasterParams.target = 0;
3539     rasterParams.source = outline;
3540     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3541     rasterParams.gray_spans = 0;
3542     rasterParams.black_spans = 0;
3543     rasterParams.bit_test = 0;
3544     rasterParams.bit_set = 0;
3545     rasterParams.user = data;
3546     rasterParams.clip_box = clip_box;
3547
3548     bool done = false;
3549     int error;
3550
3551     int rendered_spans = 0;
3552
3553     while (!done) {
3554
3555         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3556         rasterParams.gray_spans = callback;
3557         rasterParams.skip_spans = rendered_spans;
3558         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3559
3560         // Out of memory, reallocate some more and try again...
3561         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3562             rasterPoolSize *= 2;
3563             if (rasterPoolSize > 1024 * 1024) {
3564                 qWarning("QPainter: Rasterization of primitive failed");
3565                 break;
3566             }
3567
3568             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3569
3570             free(rasterPoolOnHeap);
3571             rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
3572
3573             Q_CHECK_PTR(rasterPoolOnHeap); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3574
3575             rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
3576
3577             qt_ft_grays_raster.raster_done(*grayRaster.data());
3578             qt_ft_grays_raster.raster_new(grayRaster.data());
3579             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3580         } else {
3581             done = true;
3582         }
3583     }
3584
3585     free(rasterPoolOnHeap);
3586 }
3587
3588 void QRasterPaintEnginePrivate::recalculateFastImages()
3589 {
3590     Q_Q(QRasterPaintEngine);
3591     QRasterPaintEngineState *s = q->state();
3592
3593     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3594                            && s->matrix.type() <= QTransform::TxShear;
3595 }
3596
3597 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3598 {
3599     Q_Q(const QRasterPaintEngine);
3600     const QRasterPaintEngineState *s = q->state();
3601
3602     return s->flags.fast_images
3603            && (mode == QPainter::CompositionMode_SourceOver
3604                || (mode == QPainter::CompositionMode_Source
3605                    && !image.hasAlphaChannel()));
3606 }
3607
3608 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3609 {
3610     Q_ASSERT(image.depth() == 1);
3611
3612     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3613     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3614
3615     QRgb fg = PREMUL(color.rgba());
3616     QRgb bg = 0;
3617
3618     int height = sourceImage.height();
3619     int width = sourceImage.width();
3620     for (int y=0; y<height; ++y) {
3621         uchar *source = sourceImage.scanLine(y);
3622         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3623         if (!source || !target)
3624             QT_THROW(std::bad_alloc()); // we must have run out of memory
3625         for (int x=0; x < width; ++x)
3626             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3627     }
3628     return dest;
3629 }
3630
3631 QRasterBuffer::~QRasterBuffer()
3632 {
3633 }
3634
3635 void QRasterBuffer::init()
3636 {
3637     compositionMode = QPainter::CompositionMode_SourceOver;
3638     monoDestinationWithClut = false;
3639     destColor0 = 0;
3640     destColor1 = 0;
3641 }
3642
3643 QImage::Format QRasterBuffer::prepare(QImage *image)
3644 {
3645     m_buffer = (uchar *)image->bits();
3646     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3647     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3648     bytes_per_pixel = image->depth()/8;
3649     bytes_per_line = image->bytesPerLine();
3650
3651     format = image->format();
3652     drawHelper = qDrawHelper + format;
3653     if (image->depth() == 1 && image->colorTable().size() == 2) {
3654         monoDestinationWithClut = true;
3655         destColor0 = PREMUL(image->colorTable()[0]);
3656         destColor1 = PREMUL(image->colorTable()[1]);
3657     }
3658
3659     return format;
3660 }
3661
3662 void QRasterBuffer::resetBuffer(int val)
3663 {
3664     memset(m_buffer, val, m_height*bytes_per_line);
3665 }
3666
3667 QClipData::QClipData(int height)
3668 {
3669     clipSpanHeight = height;
3670     m_clipLines = 0;
3671
3672     allocated = 0;
3673     m_spans = 0;
3674     xmin = xmax = ymin = ymax = 0;
3675     count = 0;
3676
3677     enabled = true;
3678     hasRectClip = hasRegionClip = false;
3679 }
3680
3681 QClipData::~QClipData()
3682 {
3683     if (m_clipLines)
3684         free(m_clipLines);
3685     if (m_spans)
3686         free(m_spans);
3687 }
3688
3689 void QClipData::initialize()
3690 {
3691     if (m_spans)
3692         return;
3693
3694     if (!m_clipLines)
3695         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
3696
3697     Q_CHECK_PTR(m_clipLines);
3698     QT_TRY {
3699         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
3700         allocated = clipSpanHeight;
3701         Q_CHECK_PTR(m_spans);
3702
3703         QT_TRY {
3704             if (hasRectClip) {
3705                 int y = 0;
3706                 while (y < ymin) {
3707                     m_clipLines[y].spans = 0;
3708                     m_clipLines[y].count = 0;
3709                     ++y;
3710                 }
3711
3712                 const int len = clipRect.width();
3713                 count = 0;
3714                 while (y < ymax) {
3715                     QSpan *span = m_spans + count;
3716                     span->x = xmin;
3717                     span->len = len;
3718                     span->y = y;
3719                     span->coverage = 255;
3720                     ++count;
3721
3722                     m_clipLines[y].spans = span;
3723                     m_clipLines[y].count = 1;
3724                     ++y;
3725                 }
3726
3727                 while (y < clipSpanHeight) {
3728                     m_clipLines[y].spans = 0;
3729                     m_clipLines[y].count = 0;
3730                     ++y;
3731                 }
3732             } else if (hasRegionClip) {
3733
3734                 const QVector<QRect> rects = clipRegion.rects();
3735                 const int numRects = rects.size();
3736
3737                 { // resize
3738                     const int maxSpans = (ymax - ymin) * numRects;
3739                     if (maxSpans > allocated) {
3740                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
3741                         allocated = maxSpans;
3742                     }
3743                 }
3744
3745                 int y = 0;
3746                 int firstInBand = 0;
3747                 count = 0;
3748                 while (firstInBand < numRects) {
3749                     const int currMinY = rects.at(firstInBand).y();
3750                     const int currMaxY = currMinY + rects.at(firstInBand).height();
3751
3752                     while (y < currMinY) {
3753                         m_clipLines[y].spans = 0;
3754                         m_clipLines[y].count = 0;
3755                         ++y;
3756                     }
3757
3758                     int lastInBand = firstInBand;
3759                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
3760                         ++lastInBand;
3761
3762                     while (y < currMaxY) {
3763
3764                         m_clipLines[y].spans = m_spans + count;
3765                         m_clipLines[y].count = lastInBand - firstInBand + 1;
3766
3767                         for (int r = firstInBand; r <= lastInBand; ++r) {
3768                             const QRect &currRect = rects.at(r);
3769                             QSpan *span = m_spans + count;
3770                             span->x = currRect.x();
3771                             span->len = currRect.width();
3772                             span->y = y;
3773                             span->coverage = 255;
3774                             ++count;
3775                         }
3776                         ++y;
3777                     }
3778
3779                     firstInBand = lastInBand + 1;
3780                 }
3781
3782                 Q_ASSERT(count <= allocated);
3783
3784                 while (y < clipSpanHeight) {
3785                     m_clipLines[y].spans = 0;
3786                     m_clipLines[y].count = 0;
3787                     ++y;
3788                 }
3789
3790             }
3791         } QT_CATCH(...) {
3792             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
3793             m_spans = 0;
3794             QT_RETHROW;
3795         }
3796     } QT_CATCH(...) {
3797         free(m_clipLines); // same for clipLines
3798         m_clipLines = 0;
3799         QT_RETHROW;
3800     }
3801 }
3802
3803 void QClipData::fixup()
3804 {
3805     Q_ASSERT(m_spans);
3806
3807     if (count == 0) {
3808         ymin = ymax = xmin = xmax = 0;
3809         return;
3810     }
3811
3812     int y = -1;
3813     ymin = m_spans[0].y;
3814     ymax = m_spans[count-1].y + 1;
3815     xmin = INT_MAX;
3816     xmax = 0;
3817
3818     const int firstLeft = m_spans[0].x;
3819     const int firstRight = m_spans[0].x + m_spans[0].len;
3820     bool isRect = true;
3821
3822     for (int i = 0; i < count; ++i) {
3823         QT_FT_Span_& span = m_spans[i];
3824
3825         if (span.y != y) {
3826             if (span.y != y + 1 && y != -1)
3827                 isRect = false;
3828             y = span.y;
3829             m_clipLines[y].spans = &span;
3830             m_clipLines[y].count = 1;
3831         } else
3832             ++m_clipLines[y].count;
3833
3834         const int spanLeft = span.x;
3835         const int spanRight = spanLeft + span.len;
3836
3837         if (spanLeft < xmin)
3838             xmin = spanLeft;
3839
3840         if (spanRight > xmax)
3841             xmax = spanRight;
3842
3843         if (spanLeft != firstLeft || spanRight != firstRight)
3844             isRect = false;
3845     }
3846
3847     if (isRect) {
3848         hasRectClip = true;
3849         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3850     }
3851 }
3852
3853 /*
3854     Convert \a rect to clip spans.
3855  */
3856 void QClipData::setClipRect(const QRect &rect)
3857 {
3858     if (hasRectClip && rect == clipRect)
3859         return;
3860
3861 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
3862     hasRectClip = true;
3863     hasRegionClip = false;
3864     clipRect = rect;
3865
3866     xmin = rect.x();
3867     xmax = rect.x() + rect.width();
3868     ymin = qMin(rect.y(), clipSpanHeight);
3869     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
3870
3871     if (m_spans) {
3872         free(m_spans);
3873         m_spans = 0;
3874     }
3875
3876 //    qDebug() << xmin << xmax << ymin << ymax;
3877 }
3878
3879 /*
3880     Convert \a region to clip spans.
3881  */
3882 void QClipData::setClipRegion(const QRegion &region)
3883 {
3884     if (region.rectCount() == 1) {
3885         setClipRect(region.rects().at(0));
3886         return;
3887     }
3888
3889     hasRegionClip = true;
3890     hasRectClip = false;
3891     clipRegion = region;
3892
3893     { // set bounding rect
3894         const QRect rect = region.boundingRect();
3895         xmin = rect.x();
3896         xmax = rect.x() + rect.width();
3897         ymin = rect.y();
3898         ymax = rect.y() + rect.height();
3899     }
3900
3901     if (m_spans) {
3902         free(m_spans);
3903         m_spans = 0;
3904     }
3905
3906 }
3907
3908 /*!
3909     \internal
3910     spans must be sorted on y
3911 */
3912 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
3913                                        const QSpan *spans, const QSpan *end,
3914                                        QSpan **outSpans, int available)
3915 {
3916     const_cast<QClipData *>(clip)->initialize();
3917
3918     QSpan *out = *outSpans;
3919
3920     const QSpan *clipSpans = clip->m_spans + *currentClip;
3921     const QSpan *clipEnd = clip->m_spans + clip->count;
3922
3923     while (available && spans < end ) {
3924         if (clipSpans >= clipEnd) {
3925             spans = end;
3926             break;
3927         }
3928         if (clipSpans->y > spans->y) {
3929             ++spans;
3930             continue;
3931         }
3932         if (spans->y != clipSpans->y) {
3933             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
3934                 clipSpans = clip->m_clipLines[spans->y].spans;
3935             else
3936                 ++clipSpans;
3937             continue;
3938         }
3939         Q_ASSERT(spans->y == clipSpans->y);
3940
3941         int sx1 = spans->x;
3942         int sx2 = sx1 + spans->len;
3943         int cx1 = clipSpans->x;
3944         int cx2 = cx1 + clipSpans->len;
3945
3946         if (cx1 < sx1 && cx2 < sx1) {
3947             ++clipSpans;
3948             continue;
3949         } else if (sx1 < cx1 && sx2 < cx1) {
3950             ++spans;
3951             continue;
3952         }
3953         int x = qMax(sx1, cx1);
3954         int len = qMin(sx2, cx2) - x;
3955         if (len) {
3956             out->x = qMax(sx1, cx1);
3957             out->len = qMin(sx2, cx2) - out->x;
3958             out->y = spans->y;
3959             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
3960             ++out;
3961             --available;
3962         }
3963         if (sx2 < cx2) {
3964             ++spans;
3965         } else {
3966             ++clipSpans;
3967         }
3968     }
3969
3970     *outSpans = out;
3971     *currentClip = clipSpans - clip->m_spans;
3972     return spans;
3973 }
3974
3975 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
3976 {
3977 //     qDebug() << "qt_span_fill_clipped" << spanCount;
3978     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
3979
3980     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
3981
3982     const int NSPANS = 256;
3983     QSpan cspans[NSPANS];
3984     int currentClip = 0;
3985     const QSpan *end = spans + spanCount;
3986     while (spans < end) {
3987         QSpan *clipped = cspans;
3988         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
3989 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
3990 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
3991
3992         if (clipped - cspans)
3993             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
3994     }
3995 }
3996
3997 /*
3998     \internal
3999     Clip spans to \a{clip}-rectangle.
4000     Returns number of unclipped spans
4001 */
4002 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4003                               const QRect &clip)
4004 {
4005     const short minx = clip.left();
4006     const short miny = clip.top();
4007     const short maxx = clip.right();
4008     const short maxy = clip.bottom();
4009
4010     int n = 0;
4011     for (int i = 0; i < numSpans; ++i) {
4012         if (spans[i].y > maxy)
4013             break;
4014         if (spans[i].y < miny
4015             || spans[i].x > maxx
4016             || spans[i].x + spans[i].len <= minx) {
4017             continue;
4018         }
4019         if (spans[i].x < minx) {
4020             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4021             spans[n].x = minx;
4022         } else {
4023             spans[n].x = spans[i].x;
4024             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4025         }
4026         if (spans[n].len == 0)
4027             continue;
4028         spans[n].y = spans[i].y;
4029         spans[n].coverage = spans[i].coverage;
4030         ++n;
4031     }
4032     return n;
4033 }
4034
4035
4036 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4037                                   void *userData)
4038 {
4039     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4040     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4041
4042     Q_ASSERT(fillData->clip);
4043     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4044
4045     // hw: check if this const_cast<> is safe!!!
4046     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4047                                fillData->clip->clipRect);
4048     if (count > 0)
4049         fillData->unclipped_blend(count, spans, fillData);
4050 }
4051
4052 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4053 {
4054     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4055
4056 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
4057 //     for (int i = 0; i < qMin(count, 10); ++i) {
4058 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4059 //     }
4060
4061     switch (clipData->operation) {
4062
4063     case Qt::IntersectClip:
4064         {
4065             QClipData *newClip = clipData->newClip;
4066             newClip->initialize();
4067
4068             int currentClip = 0;
4069             const QSpan *end = spans + count;
4070             while (spans < end) {
4071                 QSpan *newspans = newClip->m_spans + newClip->count;
4072                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
4073                                            &newspans, newClip->allocated - newClip->count);
4074                 newClip->count = newspans - newClip->m_spans;
4075                 if (spans < end) {
4076                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4077                     newClip->allocated *= 2;
4078                 }
4079             }
4080         }
4081         break;
4082
4083     case Qt::ReplaceClip:
4084         clipData->newClip->appendSpans(spans, count);
4085         break;
4086     case Qt::NoClip:
4087         break;
4088     }
4089 }
4090
4091 #ifndef QT_NO_DEBUG
4092 QImage QRasterBuffer::bufferImage() const
4093 {
4094     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4095
4096     for (int y = 0; y < m_height; ++y) {
4097         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4098
4099         for (int x=0; x<m_width; ++x) {
4100             uint argb = span[x];
4101             image.setPixel(x, y, argb);
4102         }
4103     }
4104     return image;
4105 }
4106 #endif
4107
4108
4109 void QRasterBuffer::flushToARGBImage(QImage *target) const
4110 {
4111     int w = qMin(m_width, target->width());
4112     int h = qMin(m_height, target->height());
4113
4114     for (int y=0; y<h; ++y) {
4115         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4116         QRgb *dest = (QRgb *) target->scanLine(y);
4117         for (int x=0; x<w; ++x) {
4118             QRgb pixel = sourceLine[x];
4119             int alpha = qAlpha(pixel);
4120             if (!alpha) {
4121                 dest[x] = 0;
4122             } else {
4123                 dest[x] = (alpha << 24)
4124                         | ((255*qRed(pixel)/alpha) << 16)
4125                         | ((255*qGreen(pixel)/alpha) << 8)
4126                         | ((255*qBlue(pixel)/alpha) << 0);
4127             }
4128         }
4129     }
4130 }
4131
4132
4133 class QGradientCache
4134 {
4135     struct CacheInfo
4136     {
4137         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4138             stops(s), opacity(op), interpolationMode(mode) {}
4139         uint buffer[GRADIENT_STOPTABLE_SIZE];
4140         QGradientStops stops;
4141         int opacity;
4142         QGradient::InterpolationMode interpolationMode;
4143     };
4144
4145     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4146
4147 public:
4148     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4149         quint64 hash_val = 0;
4150
4151         QGradientStops stops = gradient.stops();
4152         for (int i = 0; i < stops.size() && i <= 2; i++)
4153             hash_val += stops[i].second.rgba();
4154
4155         QMutexLocker lock(&mutex);
4156         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4157
4158         if (it == cache.constEnd())
4159             return addCacheElement(hash_val, gradient, opacity);
4160         else {
4161             do {
4162                 const CacheInfo &cache_info = it.value();
4163                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4164                     return cache_info.buffer;
4165                 ++it;
4166             } while (it != cache.constEnd() && it.key() == hash_val);
4167             // an exact match for these stops and opacity was not found, create new cache
4168             return addCacheElement(hash_val, gradient, opacity);
4169         }
4170     }
4171
4172     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4173 protected:
4174     inline int maxCacheSize() const { return 60; }
4175     inline void generateGradientColorTable(const QGradient& g,
4176                                            uint *colorTable,
4177                                            int size, int opacity) const;
4178     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4179         if (cache.size() == maxCacheSize()) {
4180             // may remove more than 1, but OK
4181             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4182         }
4183         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4184         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4185         return cache.insert(hash_val, cache_entry).value().buffer;
4186     }
4187
4188     QGradientColorTableHash cache;
4189     QMutex mutex;
4190 };
4191
4192 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4193 {
4194     QGradientStops stops = gradient.stops();
4195     int stopCount = stops.count();
4196     Q_ASSERT(stopCount > 0);
4197
4198     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4199
4200     if (stopCount == 2) {
4201         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4202         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4203
4204         qreal first_stop = stops[0].first;
4205         qreal second_stop = stops[1].first;
4206
4207         if (second_stop < first_stop) {
4208             qSwap(first_color, second_color);
4209             qSwap(first_stop, second_stop);
4210         }
4211
4212         if (colorInterpolation) {
4213             first_color = PREMUL(first_color);
4214             second_color = PREMUL(second_color);
4215         }
4216
4217         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4218         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4219
4220         uint red_first = qRed(first_color) << 16;
4221         uint green_first = qGreen(first_color) << 16;
4222         uint blue_first = qBlue(first_color) << 16;
4223         uint alpha_first = qAlpha(first_color) << 16;
4224
4225         uint red_second = qRed(second_color) << 16;
4226         uint green_second = qGreen(second_color) << 16;
4227         uint blue_second = qBlue(second_color) << 16;
4228         uint alpha_second = qAlpha(second_color) << 16;
4229
4230         int i = 0;
4231         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4232             if (colorInterpolation)
4233                 colorTable[i] = first_color;
4234             else
4235                 colorTable[i] = PREMUL(first_color);
4236         }
4237
4238         if (i < second_index) {
4239             qreal reciprocal = qreal(1) / (second_index - first_index);
4240
4241             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4242             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4243             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4244             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4245
4246             // rounding
4247             red_first += 1 << 15;
4248             green_first += 1 << 15;
4249             blue_first += 1 << 15;
4250             alpha_first += 1 << 15;
4251
4252             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4253                 red_first += red_delta;
4254                 green_first += green_delta;
4255                 blue_first += blue_delta;
4256                 alpha_first += alpha_delta;
4257
4258                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4259                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4260
4261                 if (colorInterpolation)
4262                     colorTable[i] = color;
4263                 else
4264                     colorTable[i] = PREMUL(color);
4265             }
4266         }
4267
4268         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4269             if (colorInterpolation)
4270                 colorTable[i] = second_color;
4271             else
4272                 colorTable[i] = PREMUL(second_color);
4273         }
4274
4275         return;
4276     }
4277
4278     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4279     if (stopCount == 1) {
4280         current_color = PREMUL(current_color);
4281         for (int i = 0; i < size; ++i)
4282             colorTable[i] = current_color;
4283         return;
4284     }
4285
4286     // The position where the gradient begins and ends
4287     qreal begin_pos = stops[0].first;
4288     qreal end_pos = stops[stopCount-1].first;
4289
4290     int pos = 0; // The position in the color table.
4291     uint next_color;
4292
4293     qreal incr = 1 / qreal(size); // the double increment.
4294     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4295
4296      // Up to first point
4297     colorTable[pos++] = PREMUL(current_color);
4298     while (dpos <= begin_pos) {
4299         colorTable[pos] = colorTable[pos - 1];
4300         ++pos;
4301         dpos += incr;
4302     }
4303
4304     int current_stop = 0; // We always interpolate between current and current + 1.
4305
4306     qreal t; // position between current left and right stops
4307     qreal t_delta; // the t increment per entry in the color table
4308
4309     if (dpos < end_pos) {
4310         // Gradient area
4311         while (dpos > stops[current_stop+1].first)
4312             ++current_stop;
4313
4314         if (current_stop != 0)
4315             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4316         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4317
4318         if (colorInterpolation) {
4319             current_color = PREMUL(current_color);
4320             next_color = PREMUL(next_color);
4321         }
4322
4323         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4324         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4325         t = (dpos - stops[current_stop].first) * c;
4326         t_delta = incr * c;
4327
4328         while (true) {
4329             Q_ASSERT(current_stop < stopCount);
4330
4331             int dist = qRound(t);
4332             int idist = 256 - dist;
4333
4334             if (colorInterpolation)
4335                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4336             else
4337                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4338
4339             ++pos;
4340             dpos += incr;
4341
4342             if (dpos >= end_pos)
4343                 break;
4344
4345             t += t_delta;
4346
4347             int skip = 0;
4348             while (dpos > stops[current_stop+skip+1].first)
4349                 ++skip;
4350
4351             if (skip != 0) {
4352                 current_stop += skip;
4353                 if (skip == 1)
4354                     current_color = next_color;
4355                 else
4356                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4357                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4358
4359                 if (colorInterpolation) {
4360                     if (skip != 1)
4361                         current_color = PREMUL(current_color);
4362                     next_color = PREMUL(next_color);
4363                 }
4364
4365                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4366                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4367                 t = (dpos - stops[current_stop].first) * c;
4368                 t_delta = incr * c;
4369             }
4370         }
4371     }
4372
4373     // After last point
4374     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4375     while (pos < size - 1) {
4376         colorTable[pos] = current_color;
4377         ++pos;
4378     }
4379
4380     // Make sure the last color stop is represented at the end of the table
4381     colorTable[size - 1] = current_color;
4382 }
4383
4384 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4385
4386
4387 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4388 {
4389     rasterBuffer = rb;
4390     type = None;
4391     txop = 0;
4392     bilinear = false;
4393     m11 = m22 = m33 = 1.;
4394     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4395     clip = pe ? pe->d_func()->clip() : 0;
4396 }
4397
4398 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4399
4400 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4401 {
4402     Qt::BrushStyle brushStyle = qbrush_style(brush);
4403     switch (brushStyle) {
4404     case Qt::SolidPattern: {
4405         type = Solid;
4406         QColor c = qbrush_color(brush);
4407         QRgb rgba = c.rgba();
4408         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4409         if ((solid.color & 0xff000000) == 0
4410             && compositionMode == QPainter::CompositionMode_SourceOver) {
4411             type = None;
4412         }
4413         break;
4414     }
4415
4416     case Qt::LinearGradientPattern:
4417         {
4418             type = LinearGradient;
4419             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4420             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4421             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4422             gradient.spread = g->spread();
4423
4424             QLinearGradientData &linearData = gradient.linear;
4425
4426             linearData.origin.x = g->start().x();
4427             linearData.origin.y = g->start().y();
4428             linearData.end.x = g->finalStop().x();
4429             linearData.end.y = g->finalStop().y();
4430             break;
4431         }
4432
4433     case Qt::RadialGradientPattern:
4434         {
4435             type = RadialGradient;
4436             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4437             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4438             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4439             gradient.spread = g->spread();
4440
4441             QRadialGradientData &radialData = gradient.radial;
4442
4443             QPointF center = g->center();
4444             radialData.center.x = center.x();
4445             radialData.center.y = center.y();
4446             radialData.center.radius = g->centerRadius();
4447             QPointF focal = g->focalPoint();
4448             radialData.focal.x = focal.x();
4449             radialData.focal.y = focal.y();
4450             radialData.focal.radius = g->focalRadius();
4451         }
4452         break;
4453
4454     case Qt::ConicalGradientPattern:
4455         {
4456             type = ConicalGradient;
4457             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4458             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4459             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4460             gradient.spread = QGradient::RepeatSpread;
4461
4462             QConicalGradientData &conicalData = gradient.conical;
4463
4464             QPointF center = g->center();
4465             conicalData.center.x = center.x();
4466             conicalData.center.y = center.y();
4467             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4468         }
4469         break;
4470
4471     case Qt::Dense1Pattern:
4472     case Qt::Dense2Pattern:
4473     case Qt::Dense3Pattern:
4474     case Qt::Dense4Pattern:
4475     case Qt::Dense5Pattern:
4476     case Qt::Dense6Pattern:
4477     case Qt::Dense7Pattern:
4478     case Qt::HorPattern:
4479     case Qt::VerPattern:
4480     case Qt::CrossPattern:
4481     case Qt::BDiagPattern:
4482     case Qt::FDiagPattern:
4483     case Qt::DiagCrossPattern:
4484         type = Texture;
4485         if (!tempImage)
4486             tempImage = new QImage();
4487         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4488         initTexture(tempImage, alpha, QTextureData::Tiled);
4489         break;
4490     case Qt::TexturePattern:
4491         type = Texture;
4492         if (!tempImage)
4493             tempImage = new QImage();
4494
4495         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4496             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4497         else
4498             *tempImage = brush.textureImage();
4499         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4500         break;
4501
4502     case Qt::NoBrush:
4503     default:
4504         type = None;
4505         break;
4506     }
4507     adjustSpanMethods();
4508 }
4509
4510 void QSpanData::adjustSpanMethods()
4511 {
4512     bitmapBlit = 0;
4513     alphamapBlit = 0;
4514     alphaRGBBlit = 0;
4515
4516     fillRect = 0;
4517
4518     switch(type) {
4519     case None:
4520         unclipped_blend = 0;
4521         break;
4522     case Solid:
4523         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4524         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4525         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4526         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4527         fillRect = rasterBuffer->drawHelper->fillRect;
4528         break;
4529     case LinearGradient:
4530     case RadialGradient:
4531     case ConicalGradient:
4532         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4533         break;
4534     case Texture:
4535         unclipped_blend = qBlendTexture;
4536         if (!texture.imageData)
4537             unclipped_blend = 0;
4538
4539         break;
4540     }
4541     // setup clipping
4542     if (!unclipped_blend) {
4543         blend = 0;
4544     } else if (!clip) {
4545         blend = unclipped_blend;
4546     } else if (clip->hasRectClip) {
4547         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4548     } else {
4549         blend = qt_span_fill_clipped;
4550     }
4551 }
4552
4553 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4554 {
4555     QTransform delta;
4556     // make sure we round off correctly in qdrawhelper.cpp
4557     delta.translate(1.0 / 65536, 1.0 / 65536);
4558
4559     QTransform inv = (delta * matrix).inverted();
4560     m11 = inv.m11();
4561     m12 = inv.m12();
4562     m13 = inv.m13();
4563     m21 = inv.m21();
4564     m22 = inv.m22();
4565     m23 = inv.m23();
4566     m33 = inv.m33();
4567     dx = inv.dx();
4568     dy = inv.dy();
4569     txop = inv.type();
4570     bilinear = bilin;
4571
4572     const bool affine = !m13 && !m23;
4573     fast_matrix = affine
4574         && m11 * m11 + m21 * m21 < 1e4
4575         && m12 * m12 + m22 * m22 < 1e4
4576         && qAbs(dx) < 1e4
4577         && qAbs(dy) < 1e4;
4578
4579     adjustSpanMethods();
4580 }
4581
4582 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4583 {
4584     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4585     if (!d || d->height == 0) {
4586         texture.imageData = 0;
4587         texture.width = 0;
4588         texture.height = 0;
4589         texture.x1 = 0;
4590         texture.y1 = 0;
4591         texture.x2 = 0;
4592         texture.y2 = 0;
4593         texture.bytesPerLine = 0;
4594         texture.format = QImage::Format_Invalid;
4595         texture.colorTable = 0;
4596         texture.hasAlpha = alpha != 256;
4597     } else {
4598         texture.imageData = d->data;
4599         texture.width = d->width;
4600         texture.height = d->height;
4601
4602         if (sourceRect.isNull()) {
4603             texture.x1 = 0;
4604             texture.y1 = 0;
4605             texture.x2 = texture.width;
4606             texture.y2 = texture.height;
4607         } else {
4608             texture.x1 = sourceRect.x();
4609             texture.y1 = sourceRect.y();
4610             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4611             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4612         }
4613
4614         texture.bytesPerLine = d->bytes_per_line;
4615
4616         texture.format = d->format;
4617         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4618         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4619     }
4620     texture.const_alpha = alpha;
4621     texture.type = _type;
4622
4623     adjustSpanMethods();
4624 }
4625
4626 /*!
4627     \internal
4628     \a x and \a y is relative to the midpoint of \a rect.
4629 */
4630 static inline void drawEllipsePoints(int x, int y, int length,
4631                                      const QRect &rect,
4632                                      const QRect &clip,
4633                                      ProcessSpans pen_func, ProcessSpans brush_func,
4634                                      QSpanData *pen_data, QSpanData *brush_data)
4635 {
4636     if (length == 0)
4637         return;
4638
4639     QT_FT_Span outline[4];
4640     const int midx = rect.x() + (rect.width() + 1) / 2;
4641     const int midy = rect.y() + (rect.height() + 1) / 2;
4642
4643     x = x + midx;
4644     y = midy - y;
4645
4646     // topleft
4647     outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
4648     outline[0].len = qMin(length, x - outline[0].x);
4649     outline[0].y = y;
4650     outline[0].coverage = 255;
4651
4652     // topright
4653     outline[1].x = x;
4654     outline[1].len = length;
4655     outline[1].y = y;
4656     outline[1].coverage = 255;
4657
4658     // bottomleft
4659     outline[2].x = outline[0].x;
4660     outline[2].len = outline[0].len;
4661     outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
4662     outline[2].coverage = 255;
4663
4664     // bottomright
4665     outline[3].x = x;
4666     outline[3].len = length;
4667     outline[3].y = outline[2].y;
4668     outline[3].coverage = 255;
4669
4670     if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
4671         QT_FT_Span fill[2];
4672
4673         // top fill
4674         fill[0].x = outline[0].x + outline[0].len - 1;
4675         fill[0].len = qMax(0, outline[1].x - fill[0].x);
4676         fill[0].y = outline[1].y;
4677         fill[0].coverage = 255;
4678
4679         // bottom fill
4680         fill[1].x = outline[2].x + outline[2].len - 1;
4681         fill[1].len = qMax(0, outline[3].x - fill[1].x);
4682         fill[1].y = outline[3].y;
4683         fill[1].coverage = 255;
4684
4685         int n = (fill[0].y >= fill[1].y ? 1 : 2);
4686         n = qt_intersect_spans(fill, n, clip);
4687         if (n > 0)
4688             brush_func(n, fill, brush_data);
4689     }
4690     if (pen_func) {
4691         int n = (outline[1].y >= outline[2].y ? 2 : 4);
4692         n = qt_intersect_spans(outline, n, clip);
4693         if (n > 0)
4694             pen_func(n, outline, pen_data);
4695     }
4696 }
4697
4698 /*!
4699     \internal
4700     Draws an ellipse using the integer point midpoint algorithm.
4701 */
4702 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
4703                                    ProcessSpans pen_func, ProcessSpans brush_func,
4704                                    QSpanData *pen_data, QSpanData *brush_data)
4705 {
4706     const qreal a = qreal(rect.width()) / 2;
4707     const qreal b = qreal(rect.height()) / 2;
4708     qreal d = b*b - (a*a*b) + 0.25*a*a;
4709
4710     int x = 0;
4711     int y = (rect.height() + 1) / 2;
4712     int startx = x;
4713
4714     // region 1
4715     while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
4716         if (d < 0) { // select E
4717             d += b*b*(2*x + 3);
4718             ++x;
4719         } else {     // select SE
4720             d += b*b*(2*x + 3) + a*a*(-2*y + 2);
4721             drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4722                               pen_func, brush_func, pen_data, brush_data);
4723             startx = ++x;
4724             --y;
4725         }
4726     }
4727     drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4728                       pen_func, brush_func, pen_data, brush_data);
4729
4730     // region 2
4731     d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
4732     const int miny = rect.height() & 0x1;
4733     while (y > miny) {
4734         if (d < 0) { // select SE
4735             d += b*b*(2*x + 2) + a*a*(-2*y + 3);
4736             ++x;
4737         } else {     // select S
4738             d += a*a*(-2*y + 3);
4739         }
4740         --y;
4741         drawEllipsePoints(x, y, 1, rect, clip,
4742                           pen_func, brush_func, pen_data, brush_data);
4743     }
4744 }
4745
4746 /*!
4747     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
4748     \overload
4749     \reimp
4750 */
4751
4752
4753 #ifdef QT_DEBUG_DRAW
4754 void dumpClip(int width, int height, const QClipData *clip)
4755 {
4756     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4757     clipImg.fill(0xffff0000);
4758
4759     int x0 = width;
4760     int x1 = 0;
4761     int y0 = height;
4762     int y1 = 0;
4763
4764     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
4765
4766     for (int i = 0; i < clip->count; ++i) {
4767         const QSpan *span = ((QClipData *) clip)->spans() + i;
4768         for (int j = 0; j < span->len; ++j)
4769             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4770         x0 = qMin(x0, int(span->x));
4771         x1 = qMax(x1, int(span->x + span->len - 1));
4772
4773         y0 = qMin(y0, int(span->y));
4774         y1 = qMax(y1, int(span->y));
4775     }
4776
4777     static int counter = 0;
4778
4779     Q_ASSERT(y0 >= 0);
4780     Q_ASSERT(x0 >= 0);
4781     Q_ASSERT(y1 >= 0);
4782     Q_ASSERT(x1 >= 0);
4783
4784     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4785     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
4786 }
4787 #endif
4788
4789
4790 QT_END_NAMESPACE