46648fe29775cfe3a733d216c47885c0a9ff75f1
[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     if (q->state()) {
1076         q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1077         q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1078         q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1079     }
1080 }
1081
1082 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1083 {
1084     if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1085         return;
1086
1087     Q_Q(QRasterPaintEngine);
1088     bool bilinear = q->state()->flags.bilinear;
1089
1090     if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1091         spanData->setupMatrix(b.transform() * m, bilinear);
1092     } else {
1093         if (m.type() <= QTransform::TxTranslate) {
1094             // specialize setupMatrix for translation matrices
1095             // to avoid needless matrix inversion
1096             spanData->m11 = 1;
1097             spanData->m12 = 0;
1098             spanData->m13 = 0;
1099             spanData->m21 = 0;
1100             spanData->m22 = 1;
1101             spanData->m23 = 0;
1102             spanData->m33 = 1;
1103             spanData->dx = -m.dx();
1104             spanData->dy = -m.dy();
1105             spanData->txop = m.type();
1106             spanData->bilinear = bilinear;
1107             spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1108             spanData->adjustSpanMethods();
1109         } else {
1110             spanData->setupMatrix(m, bilinear);
1111         }
1112     }
1113 }
1114
1115 // #define QT_CLIPPING_RATIOS
1116
1117 #ifdef QT_CLIPPING_RATIOS
1118 int rectClips;
1119 int regionClips;
1120 int totalClips;
1121
1122 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1123 {
1124     if (d->clip()->hasRectClip)
1125         rectClips++;
1126     if (d->clip()->hasRegionClip)
1127         regionClips++;
1128     totalClips++;
1129
1130     if ((totalClips % 5000) == 0) {
1131         printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1132                rectClips * 100.0 / (qreal) totalClips,
1133                regionClips * 100.0 / (qreal) totalClips,
1134                (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1135         totalClips = 0;
1136         rectClips = 0;
1137         regionClips = 0;
1138     }
1139
1140 }
1141 #endif
1142
1143 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1144 {
1145     if (s->flags.has_clip_ownership)
1146         delete s->clip;
1147     s->clip = 0;
1148     s->flags.has_clip_ownership = false;
1149 }
1150
1151 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1152 {
1153     s->fillFlags |= QPaintEngine::DirtyClipPath;
1154     s->strokeFlags |= QPaintEngine::DirtyClipPath;
1155     s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1156
1157     d->solid_color_filler.clip = d->clip();
1158     d->solid_color_filler.adjustSpanMethods();
1159
1160 #ifdef QT_DEBUG_DRAW
1161     dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1162 #endif
1163
1164 }
1165
1166
1167 /*!
1168     \internal
1169 */
1170 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1171 {
1172 #ifdef QT_DEBUG_DRAW
1173     qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1174
1175     if (path.elements()) {
1176         for (int i=0; i<path.elementCount(); ++i) {
1177             qDebug() << " - " << path.elements()[i]
1178                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1179         }
1180     } else {
1181         for (int i=0; i<path.elementCount(); ++i) {
1182             qDebug() << " ---- "
1183                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1184         }
1185     }
1186 #endif
1187
1188     Q_D(QRasterPaintEngine);
1189     QRasterPaintEngineState *s = state();
1190
1191     const qreal *points = path.points();
1192     const QPainterPath::ElementType *types = path.elements();
1193
1194     // There are some cases that are not supported by clip(QRect)
1195     if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
1196         if (s->matrix.type() <= QTransform::TxScale
1197             && ((path.shape() == QVectorPath::RectangleHint)
1198                 || (isRect(points, path.elementCount())
1199                     && (!types || (types[0] == QPainterPath::MoveToElement
1200                                    && types[1] == QPainterPath::LineToElement
1201                                    && types[2] == QPainterPath::LineToElement
1202                                    && types[3] == QPainterPath::LineToElement))))) {
1203 #ifdef QT_DEBUG_DRAW
1204             qDebug() << " --- optimizing vector clip to rect clip...";
1205 #endif
1206
1207             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1208             if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
1209                 return;
1210         }
1211     }
1212
1213     if (op == Qt::NoClip) {
1214         qrasterpaintengine_state_setNoClip(s);
1215
1216     } else {
1217         QClipData *base = d->baseClip.data();
1218
1219         // Intersect with current clip when available...
1220         if (op == Qt::IntersectClip && s->clip)
1221             base = s->clip;
1222
1223         // We always intersect, except when there is nothing to
1224         // intersect with, in which case we simplify the operation to
1225         // a replace...
1226         Qt::ClipOperation isectOp = Qt::IntersectClip;
1227         if (base == 0)
1228             isectOp = Qt::ReplaceClip;
1229
1230         QClipData *newClip = new QClipData(d->rasterBuffer->height());
1231         newClip->initialize();
1232         ClipData clipData = { base, newClip, isectOp };
1233         ensureOutlineMapper();
1234         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1235
1236         newClip->fixup();
1237
1238         if (s->flags.has_clip_ownership)
1239             delete s->clip;
1240
1241         s->clip = newClip;
1242         s->flags.has_clip_ownership = true;
1243     }
1244     qrasterpaintengine_dirty_clip(d, s);
1245 }
1246
1247
1248
1249 /*!
1250     \internal
1251 */
1252 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1253 {
1254 #ifdef QT_DEBUG_DRAW
1255     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1256 #endif
1257
1258     QRasterPaintEngineState *s = state();
1259
1260     if (op == Qt::NoClip) {
1261         qrasterpaintengine_state_setNoClip(s);
1262
1263     } else if (s->matrix.type() > QTransform::TxScale) {
1264         QPaintEngineEx::clip(rect, op);
1265         return;
1266
1267     } else if (!setClipRectInDeviceCoords(s->matrix.mapRect(rect), op)) {
1268         QPaintEngineEx::clip(rect, op);
1269         return;
1270     }
1271 }
1272
1273
1274 bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
1275 {
1276     Q_D(QRasterPaintEngine);
1277     QRect clipRect = r & d->deviceRect;
1278     QRasterPaintEngineState *s = state();
1279
1280     if (op == Qt::ReplaceClip || s->clip == 0) {
1281
1282         // No current clip, hence we intersect with sysclip and be
1283         // done with it...
1284         QRegion clipRegion = systemClip();
1285         QClipData *clip = new QClipData(d->rasterBuffer->height());
1286
1287         if (clipRegion.isEmpty())
1288             clip->setClipRect(clipRect);
1289         else
1290             clip->setClipRegion(clipRegion & clipRect);
1291
1292         if (s->flags.has_clip_ownership)
1293             delete s->clip;
1294
1295         s->clip = clip;
1296         s->clip->enabled = true;
1297         s->flags.has_clip_ownership = true;
1298
1299     } else if (op == Qt::IntersectClip){ // intersect clip with current clip
1300         QClipData *base = s->clip;
1301
1302         Q_ASSERT(base);
1303         if (base->hasRectClip || base->hasRegionClip) {
1304             if (!s->flags.has_clip_ownership) {
1305                 s->clip = new QClipData(d->rasterBuffer->height());
1306                 s->flags.has_clip_ownership = true;
1307             }
1308             if (base->hasRectClip)
1309                 s->clip->setClipRect(base->clipRect & clipRect);
1310             else
1311                 s->clip->setClipRegion(base->clipRegion & clipRect);
1312             s->clip->enabled = true;
1313         } else {
1314             return false;
1315         }
1316     } else {
1317         return false;
1318     }
1319
1320     qrasterpaintengine_dirty_clip(d, s);
1321     return true;
1322 }
1323
1324
1325 /*!
1326     \internal
1327 */
1328 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1329 {
1330 #ifdef QT_DEBUG_DRAW
1331     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1332 #endif
1333
1334     Q_D(QRasterPaintEngine);
1335
1336     if (region.rectCount() == 1) {
1337         clip(region.boundingRect(), op);
1338         return;
1339     }
1340
1341     QRasterPaintEngineState *s = state();
1342     const QClipData *clip = d->clip();
1343     const QClipData *baseClip = d->baseClip.data();
1344
1345     if (op == Qt::NoClip) {
1346         qrasterpaintengine_state_setNoClip(s);
1347     } else if (s->matrix.type() > QTransform::TxScale
1348                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1349                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1350         QPaintEngineEx::clip(region, op);
1351     } else {
1352         const QClipData *curClip;
1353         QClipData *newClip;
1354
1355         if (op == Qt::IntersectClip)
1356             curClip = clip;
1357         else
1358             curClip = baseClip;
1359
1360         if (s->flags.has_clip_ownership) {
1361             newClip = s->clip;
1362             Q_ASSERT(newClip);
1363         } else {
1364             newClip = new QClipData(d->rasterBuffer->height());
1365             s->clip = newClip;
1366             s->flags.has_clip_ownership = true;
1367         }
1368
1369         QRegion r = s->matrix.map(region);
1370         if (curClip->hasRectClip)
1371             newClip->setClipRegion(r & curClip->clipRect);
1372         else if (curClip->hasRegionClip)
1373             newClip->setClipRegion(r & curClip->clipRegion);
1374
1375         qrasterpaintengine_dirty_clip(d, s);
1376     }
1377 }
1378
1379 /*!
1380  \fn const QClipData *QRasterPaintEngine::clipData() const
1381
1382  \internal
1383 */
1384
1385
1386 /*!
1387     \internal
1388 */
1389 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1390 {
1391 #ifdef QT_DEBUG_DRAW
1392     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1393 #endif
1394
1395     if (!fillData->blend)
1396         return;
1397
1398     Q_D(QRasterPaintEngine);
1399
1400     const QRectF controlPointRect = path.controlPointRect();
1401
1402     QRasterPaintEngineState *s = state();
1403     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1404     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1405     const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1406                           || deviceRect.right() > QT_RASTER_COORD_LIMIT
1407                           || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1408                           || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1409
1410     if (!s->flags.antialiased && !do_clip) {
1411         d->initializeRasterizer(fillData);
1412         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1413         return;
1414     }
1415
1416     ensureOutlineMapper();
1417     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1418 }
1419
1420 static void fillRect_normalized(const QRect &r, QSpanData *data,
1421                                 QRasterPaintEnginePrivate *pe)
1422 {
1423     int x1, x2, y1, y2;
1424
1425     bool rectClipped = true;
1426
1427     if (data->clip) {
1428         x1 = qMax(r.x(), data->clip->xmin);
1429         x2 = qMin(r.x() + r.width(), data->clip->xmax);
1430         y1 = qMax(r.y(), data->clip->ymin);
1431         y2 = qMin(r.y() + r.height(), data->clip->ymax);
1432         rectClipped = data->clip->hasRectClip;
1433
1434     } else if (pe) {
1435         x1 = qMax(r.x(), pe->deviceRect.x());
1436         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1437         y1 = qMax(r.y(), pe->deviceRect.y());
1438         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1439     } else {
1440         x1 = qMax(r.x(), 0);
1441         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1442         y1 = qMax(r.y(), 0);
1443         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1444     }
1445
1446     if (x2 <= x1 || y2 <= y1)
1447         return;
1448
1449     const int width = x2 - x1;
1450     const int height = y2 - y1;
1451
1452     bool isUnclipped = rectClipped
1453                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1454
1455     if (pe && isUnclipped) {
1456         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1457
1458         if (data->fillRect && (mode == QPainter::CompositionMode_Source
1459                                || (mode == QPainter::CompositionMode_SourceOver
1460                                    && qAlpha(data->solid.color) == 255)))
1461         {
1462             data->fillRect(data->rasterBuffer, x1, y1, width, height,
1463                            data->solid.color);
1464             return;
1465         }
1466     }
1467
1468     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1469
1470     const int nspans = 256;
1471     QT_FT_Span spans[nspans];
1472
1473     Q_ASSERT(data->blend);
1474     int y = y1;
1475     while (y < y2) {
1476         int n = qMin(nspans, y2 - y);
1477         int i = 0;
1478         while (i < n) {
1479             spans[i].x = x1;
1480             spans[i].len = width;
1481             spans[i].y = y + i;
1482             spans[i].coverage = 255;
1483             ++i;
1484         }
1485
1486         blend(n, spans, data);
1487         y += n;
1488     }
1489 }
1490
1491 /*!
1492     \reimp
1493 */
1494 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1495 {
1496 #ifdef QT_DEBUG_DRAW
1497     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1498 #endif
1499     Q_D(QRasterPaintEngine);
1500     ensureRasterState();
1501     QRasterPaintEngineState *s = state();
1502
1503     // Fill
1504     ensureBrush();
1505     if (s->brushData.blend) {
1506         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1507             const QRect *r = rects;
1508             const QRect *lastRect = rects + rectCount;
1509
1510             int offset_x = int(s->matrix.dx());
1511             int offset_y = int(s->matrix.dy());
1512             while (r < lastRect) {
1513                 QRect rect = r->normalized();
1514                 QRect rr = rect.translated(offset_x, offset_y);
1515                 fillRect_normalized(rr, &s->brushData, d);
1516                 ++r;
1517             }
1518         } else {
1519             QRectVectorPath path;
1520             for (int i=0; i<rectCount; ++i) {
1521                 path.set(rects[i]);
1522                 fill(path, s->brush);
1523             }
1524         }
1525     }
1526
1527     ensurePen();
1528     if (s->penData.blend) {
1529         QRectVectorPath path;
1530         if (s->flags.fast_pen) {
1531             QCosmeticStroker stroker(s, d->deviceRect);
1532             stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
1533             for (int i = 0; i < rectCount; ++i) {
1534                 path.set(rects[i]);
1535                 stroker.drawPath(path);
1536             }
1537         } else {
1538             for (int i = 0; i < rectCount; ++i) {
1539                 path.set(rects[i]);
1540                 stroke(path, s->pen);
1541             }
1542         }
1543     }
1544 }
1545
1546 /*!
1547     \reimp
1548 */
1549 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1550 {
1551 #ifdef QT_DEBUG_DRAW
1552     qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
1553 #endif
1554 #ifdef QT_FAST_SPANS
1555     Q_D(QRasterPaintEngine);
1556     ensureRasterState();
1557     QRasterPaintEngineState *s = state();
1558
1559
1560     if (s->flags.tx_noshear) {
1561         ensureBrush();
1562         if (s->brushData.blend) {
1563             d->initializeRasterizer(&s->brushData);
1564             for (int i = 0; i < rectCount; ++i) {
1565                 const QRectF &rect = rects[i].normalized();
1566                 if (rect.isEmpty())
1567                     continue;
1568                 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1569                 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1570                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1571             }
1572         }
1573
1574         ensurePen();
1575         if (s->penData.blend) {
1576             QRectVectorPath path;
1577             if (s->flags.fast_pen) {
1578                 QCosmeticStroker stroker(s, d->deviceRect);
1579                 stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
1580                 for (int i = 0; i < rectCount; ++i) {
1581                     path.set(rects[i]);
1582                     stroker.drawPath(path);
1583                 }
1584             } else {
1585                 for (int i = 0; i < rectCount; ++i) {
1586                     path.set(rects[i]);
1587                     QPaintEngineEx::stroke(path, s->lastPen);
1588                 }
1589             }
1590         }
1591
1592         return;
1593     }
1594 #endif // QT_FAST_SPANS
1595     QPaintEngineEx::drawRects(rects, rectCount);
1596 }
1597
1598
1599 /*!
1600     \internal
1601 */
1602 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1603 {
1604     Q_D(QRasterPaintEngine);
1605     QRasterPaintEngineState *s = state();
1606
1607     ensurePen(pen);
1608     if (!s->penData.blend)
1609         return;
1610
1611     if (s->flags.fast_pen) {
1612         QCosmeticStroker stroker(s, d->deviceRect);
1613         stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
1614         stroker.drawPath(path);
1615     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1616         qreal width = qt_pen_is_cosmetic(s->lastPen, s->renderHints)
1617                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1618                       : qpen_widthf(s->lastPen) * s->txscale;
1619         int dashIndex = 0;
1620         qreal dashOffset = s->lastPen.dashOffset();
1621         bool inDash = true;
1622         qreal patternLength = 0;
1623         const QVector<qreal> pattern = s->lastPen.dashPattern();
1624         for (int i = 0; i < pattern.size(); ++i)
1625             patternLength += pattern.at(i);
1626
1627         if (patternLength > 0) {
1628             int n = qFloor(dashOffset / patternLength);
1629             dashOffset -= n * patternLength;
1630             while (dashOffset >= pattern.at(dashIndex)) {
1631                 dashOffset -= pattern.at(dashIndex);
1632                 if (++dashIndex >= pattern.size())
1633                     dashIndex = 0;
1634                 inDash = !inDash;
1635             }
1636         }
1637
1638         Q_D(QRasterPaintEngine);
1639         d->initializeRasterizer(&s->penData);
1640         int lineCount = path.elementCount() / 2;
1641         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1642
1643         for (int i = 0; i < lineCount; ++i) {
1644             if (lines[i].p1() == lines[i].p2()) {
1645                 if (s->lastPen.capStyle() != Qt::FlatCap) {
1646                     QPointF p = lines[i].p1();
1647                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1648                                                        QPointF(p.x() + width*0.5, p.y())));
1649                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1650                 }
1651                 continue;
1652             }
1653
1654             const QLineF line = s->matrix.map(lines[i]);
1655             if (qpen_style(s->lastPen) == Qt::SolidLine) {
1656                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1657                                             width / line.length(),
1658                                             s->lastPen.capStyle() == Qt::SquareCap);
1659             } else {
1660                 d->rasterizeLine_dashed(line, width,
1661                                         &dashIndex, &dashOffset, &inDash);
1662             }
1663         }
1664     }
1665     else
1666         QPaintEngineEx::stroke(path, pen);
1667 }
1668
1669 QRect QRasterPaintEngine::toNormalizedFillRect(const QRectF &rect)
1670 {
1671     QRasterPaintEngineState *s = state();
1672
1673     qreal delta = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
1674
1675     int x1 = qRound(rect.x() + delta);
1676     int y1 = qRound(rect.y() + delta);
1677     int x2 = qRound(rect.right() + delta);
1678     int y2 = qRound(rect.bottom() + delta);
1679
1680     if (x2 < x1)
1681         qSwap(x1, x2);
1682     if (y2 < y1)
1683         qSwap(y1, y2);
1684
1685     return QRect(x1, y1, x2 - x1, y2 - y1);
1686 }
1687
1688 /*!
1689     \internal
1690 */
1691 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1692 {
1693     if (path.isEmpty())
1694         return;
1695 #ifdef QT_DEBUG_DRAW
1696     QRectF rf = path.controlPointRect();
1697     qDebug() << "QRasterPaintEngine::fill(): "
1698              << "size=" << path.elementCount()
1699              << ", hints=" << hex << path.hints()
1700              << rf << brush;
1701 #endif
1702
1703     Q_D(QRasterPaintEngine);
1704     QRasterPaintEngineState *s = state();
1705
1706     ensureBrush(brush);
1707     if (!s->brushData.blend)
1708         return;
1709
1710     if (path.shape() == QVectorPath::RectangleHint) {
1711         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1712             const qreal *p = path.points();
1713             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1714             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1715             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1716             return;
1717         }
1718         ensureRasterState();
1719         if (s->flags.tx_noshear) {
1720             d->initializeRasterizer(&s->brushData);
1721             // ### Is normalizing really necessary here?
1722             const qreal *p = path.points();
1723             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1724             if (!r.isEmpty()) {
1725                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1726                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1727                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1728             }
1729             return;
1730         }
1731     }
1732
1733     // ### Optimize for non transformed ellipses and rectangles...
1734     QRectF cpRect = path.controlPointRect();
1735     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1736     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1737
1738         // ### Falcon
1739 //         const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1740 //                               || deviceRect.right() > QT_RASTER_COORD_LIMIT
1741 //                               || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1742 //                               || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1743
1744         // ### Falonc: implement....
1745 //         if (!s->flags.antialiased && !do_clip) {
1746 //             d->initializeRasterizer(&s->brushData);
1747 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1748 //             return;
1749 //         }
1750
1751     ensureOutlineMapper();
1752     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1753 }
1754
1755 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1756 {
1757     Q_D(QRasterPaintEngine);
1758     QRasterPaintEngineState *s = state();
1759
1760     if (!s->flags.antialiased) {
1761         uint txop = s->matrix.type();
1762         if (txop == QTransform::TxNone) {
1763             fillRect_normalized(toNormalizedFillRect(r), data, d);
1764             return;
1765         } else if (txop == QTransform::TxTranslate) {
1766             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1767             fillRect_normalized(rr, data, d);
1768             return;
1769         } else if (txop == QTransform::TxScale) {
1770             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1771             fillRect_normalized(rr, data, d);
1772             return;
1773         }
1774     }
1775     ensureRasterState();
1776     if (s->flags.tx_noshear) {
1777         d->initializeRasterizer(data);
1778         QRectF nr = r.normalized();
1779         if (!nr.isEmpty()) {
1780             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1781             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1782             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1783         }
1784         return;
1785     }
1786
1787     QPainterPath path;
1788     path.addRect(r);
1789     ensureOutlineMapper();
1790     fillPath(path, data);
1791 }
1792
1793 /*!
1794     \reimp
1795 */
1796 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1797 {
1798 #ifdef QT_DEBUG_DRAW
1799     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1800 #endif
1801     QRasterPaintEngineState *s = state();
1802
1803     ensureBrush(brush);
1804     if (!s->brushData.blend)
1805         return;
1806
1807     fillRect(r, &s->brushData);
1808 }
1809
1810 /*!
1811     \reimp
1812 */
1813 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1814 {
1815 #ifdef QT_DEBUG_DRAW
1816     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1817 #endif
1818     Q_D(QRasterPaintEngine);
1819     QRasterPaintEngineState *s = state();
1820
1821     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1822     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1823         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1824         return;
1825     }
1826     d->solid_color_filler.clip = d->clip();
1827     d->solid_color_filler.adjustSpanMethods();
1828     fillRect(r, &d->solid_color_filler);
1829 }
1830
1831 static inline bool isAbove(const QPointF *a, const QPointF *b)
1832 {
1833     return a->y() < b->y();
1834 }
1835
1836 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1837 {
1838     Q_ASSERT(upper);
1839     Q_ASSERT(lower);
1840
1841     Q_ASSERT(pointCount >= 2);
1842
1843     QVector<const QPointF *> sorted;
1844     sorted.reserve(pointCount);
1845
1846     upper->reserve(pointCount * 3 / 4);
1847     lower->reserve(pointCount * 3 / 4);
1848
1849     for (int i = 0; i < pointCount; ++i)
1850         sorted << points + i;
1851
1852     qSort(sorted.begin(), sorted.end(), isAbove);
1853
1854     qreal splitY = sorted.at(sorted.size() / 2)->y();
1855
1856     const QPointF *end = points + pointCount;
1857     const QPointF *last = end - 1;
1858
1859     QVector<QPointF> *bin[2] = { upper, lower };
1860
1861     for (const QPointF *p = points; p < end; ++p) {
1862         int side = p->y() < splitY;
1863         int lastSide = last->y() < splitY;
1864
1865         if (side != lastSide) {
1866             if (qFuzzyCompare(p->y(), splitY)) {
1867                 bin[!side]->append(*p);
1868             } else if (qFuzzyCompare(last->y(), splitY)) {
1869                 bin[side]->append(*last);
1870             } else {
1871                 QPointF delta = *p - *last;
1872                 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1873
1874                 bin[0]->append(intersection);
1875                 bin[1]->append(intersection);
1876             }
1877         }
1878
1879         bin[side]->append(*p);
1880
1881         last = p;
1882     }
1883
1884     // give up if we couldn't reduce the point count
1885     return upper->size() < pointCount && lower->size() < pointCount;
1886 }
1887
1888 /*!
1889   \internal
1890  */
1891 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1892 {
1893     Q_D(QRasterPaintEngine);
1894     QRasterPaintEngineState *s = state();
1895
1896     const int maxPoints = 0xffff;
1897
1898     // max amount of points that raster engine can reliably handle
1899     if (pointCount > maxPoints) {
1900         QVector<QPointF> upper, lower;
1901
1902         if (splitPolygon(points, pointCount, &upper, &lower)) {
1903             fillPolygon(upper.constData(), upper.size(), mode);
1904             fillPolygon(lower.constData(), lower.size(), mode);
1905         } else
1906             qWarning("Polygon too complex for filling.");
1907
1908         return;
1909     }
1910
1911     // Compose polygon fill..,
1912     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1913     ensureOutlineMapper();
1914     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
1915
1916     // scanconvert.
1917     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
1918                                               &s->brushData);
1919     d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
1920 }
1921
1922 /*!
1923     \reimp
1924 */
1925 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1926 {
1927     Q_D(QRasterPaintEngine);
1928     QRasterPaintEngineState *s = state();
1929
1930 #ifdef QT_DEBUG_DRAW
1931     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
1932     for (int i=0; i<pointCount; ++i)
1933         qDebug() << "   - " << points[i];
1934 #endif
1935     Q_ASSERT(pointCount >= 2);
1936
1937     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
1938         QRectF r(points[0], points[2]);
1939         drawRects(&r, 1);
1940         return;
1941     }
1942
1943     ensurePen();
1944     if (mode != PolylineMode) {
1945         // Do the fill...
1946         ensureBrush();
1947         if (s->brushData.blend)
1948             fillPolygon(points, pointCount, mode);
1949     }
1950
1951     // Do the outline...
1952     if (s->penData.blend) {
1953         QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
1954         if (s->flags.fast_pen) {
1955             QCosmeticStroker stroker(s, d->deviceRect);
1956             stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
1957             stroker.drawPath(vp);
1958         } else {
1959             QPaintEngineEx::stroke(vp, s->lastPen);
1960         }
1961     }
1962 }
1963
1964 /*!
1965     \reimp
1966 */
1967 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
1968 {
1969     Q_D(QRasterPaintEngine);
1970     QRasterPaintEngineState *s = state();
1971
1972 #ifdef QT_DEBUG_DRAW
1973     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
1974     for (int i=0; i<pointCount; ++i)
1975         qDebug() << "   - " << points[i];
1976 #endif
1977     Q_ASSERT(pointCount >= 2);
1978     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
1979         QRect r(points[0].x(),
1980                 points[0].y(),
1981                 points[2].x() - points[0].x(),
1982                 points[2].y() - points[0].y());
1983         drawRects(&r, 1);
1984         return;
1985     }
1986
1987     ensurePen();
1988
1989     // Do the fill
1990     if (mode != PolylineMode) {
1991         ensureBrush();
1992         if (s->brushData.blend) {
1993             // Compose polygon fill..,
1994             ensureOutlineMapper();
1995             d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
1996             d->outlineMapper->moveTo(*points);
1997             const QPoint *p = points;
1998             const QPoint *ep = points + pointCount - 1;
1999             do {
2000                 d->outlineMapper->lineTo(*(++p));
2001             } while (p < ep);
2002             d->outlineMapper->endOutline();
2003
2004             // scanconvert.
2005             ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2006                                                       &s->brushData);
2007             d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
2008         }
2009     }
2010
2011     // Do the outline...
2012     if (s->penData.blend) {
2013         int count = pointCount * 2;
2014         QVarLengthArray<qreal> fpoints(count);
2015         for (int i=0; i<count; ++i)
2016             fpoints[i] = ((int *) points)[i];
2017         QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2018
2019         if (s->flags.fast_pen) {
2020             QCosmeticStroker stroker(s, d->deviceRect);
2021             stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
2022             stroker.drawPath(vp);
2023         } else {
2024             QPaintEngineEx::stroke(vp, s->lastPen);
2025         }
2026     }
2027 }
2028
2029 /*!
2030     \internal
2031 */
2032 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2033 {
2034 #ifdef QT_DEBUG_DRAW
2035     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2036 #endif
2037
2038     QPlatformPixmap *pd = pixmap.handle();
2039     if (pd->classId() == QPlatformPixmap::RasterClass) {
2040         const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
2041         if (image.depth() == 1) {
2042             Q_D(QRasterPaintEngine);
2043             QRasterPaintEngineState *s = state();
2044             if (s->matrix.type() <= QTransform::TxTranslate) {
2045                 ensurePen();
2046                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2047             } else {
2048                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2049             }
2050         } else {
2051             QRasterPaintEngine::drawImage(pos, image);
2052         }
2053     } else {
2054         const QImage image = pixmap.toImage();
2055         if (pixmap.depth() == 1) {
2056             Q_D(QRasterPaintEngine);
2057             QRasterPaintEngineState *s = state();
2058             if (s->matrix.type() <= QTransform::TxTranslate) {
2059                 ensurePen();
2060                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2061             } else {
2062                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2063             }
2064         } else {
2065             QRasterPaintEngine::drawImage(pos, image);
2066         }
2067     }
2068 }
2069
2070 /*!
2071     \reimp
2072 */
2073 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2074 {
2075 #ifdef QT_DEBUG_DRAW
2076     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2077 #endif
2078
2079     QPlatformPixmap* pd = pixmap.handle();
2080     if (pd->classId() == QPlatformPixmap::RasterClass) {
2081         const QImage &image = static_cast<QRasterPlatformPixmap *>(pd)->image;
2082         if (image.depth() == 1) {
2083             Q_D(QRasterPaintEngine);
2084             QRasterPaintEngineState *s = state();
2085             if (s->matrix.type() <= QTransform::TxTranslate
2086                 && r.size() == sr.size()
2087                 && r.size() == pixmap.size()) {
2088                 ensurePen();
2089                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2090                 return;
2091             } else {
2092                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2093             }
2094         } else {
2095             drawImage(r, image, sr);
2096         }
2097     } else {
2098         QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2099         const QImage image = pd->toImage(clippedSource);
2100         QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2101         if (image.depth() == 1) {
2102             Q_D(QRasterPaintEngine);
2103             QRasterPaintEngineState *s = state();
2104             if (s->matrix.type() <= QTransform::TxTranslate
2105                 && r.size() == sr.size()
2106                 && r.size() == pixmap.size()) {
2107                 ensurePen();
2108                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2109                 return;
2110             } else {
2111                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2112             }
2113         } else {
2114             drawImage(r, image, translatedSource);
2115         }
2116     }
2117 }
2118
2119 static inline int fast_ceil_positive(const qreal &v)
2120 {
2121     const int iv = int(v);
2122     if (v - iv == 0)
2123         return iv;
2124     else
2125         return iv + 1;
2126 }
2127
2128 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2129 {
2130     const int xmin = int(rect.x());
2131     const int xmax = int(fast_ceil_positive(rect.right()));
2132     const int ymin = int(rect.y());
2133     const int ymax = int(fast_ceil_positive(rect.bottom()));
2134     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2135 }
2136
2137 /*!
2138     \internal
2139 */
2140 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2141 {
2142 #ifdef QT_DEBUG_DRAW
2143     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
2144 #endif
2145
2146     Q_D(QRasterPaintEngine);
2147     QRasterPaintEngineState *s = state();
2148     qreal scale = img.devicePixelRatio();
2149
2150     if (scale > 1.0 ||  s->matrix.type() > QTransform::TxTranslate) {
2151         drawImage(QRectF(p.x(), p.y(), img.width() / scale, img.height() / scale),
2152                   img,
2153                   QRectF(0, 0, img.width(), img.height()));
2154     } else {
2155
2156         const QClipData *clip = d->clip();
2157         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2158
2159         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2160             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2161             if (func) {
2162                 if (!clip) {
2163                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2164                     return;
2165                 } else if (clip->hasRectClip) {
2166                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2167                     return;
2168                 }
2169             }
2170         }
2171
2172
2173
2174         d->image_filler.clip = clip;
2175         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2176         if (!d->image_filler.blend)
2177             return;
2178         d->image_filler.dx = -pt.x();
2179         d->image_filler.dy = -pt.y();
2180         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2181
2182         fillRect_normalized(rr, &d->image_filler, d);
2183     }
2184
2185 }
2186
2187 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2188 {
2189     return QRectF(r.topLeft() * t, r.bottomRight() * t);
2190 }
2191
2192 namespace {
2193     enum RotationType {
2194         Rotation90,
2195         Rotation180,
2196         Rotation270,
2197         NoRotation
2198     };
2199
2200     inline RotationType qRotationType(const QTransform &transform)
2201     {
2202         QTransform::TransformationType type = transform.type();
2203
2204         if (type > QTransform::TxRotate)
2205             return NoRotation;
2206
2207         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2208             && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2209             return Rotation90;
2210
2211         if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2212             && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2213             return Rotation180;
2214
2215         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2216             && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2217             return Rotation270;
2218
2219         return NoRotation;
2220     }
2221
2222     inline bool isPixelAligned(const QRectF &rect) {
2223         return QRectF(rect.toRect()) == rect;
2224     }
2225 }
2226
2227 /*!
2228     \reimp
2229 */
2230 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2231                                    Qt::ImageConversionFlags)
2232 {
2233 #ifdef QT_DEBUG_DRAW
2234     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2235 #endif
2236
2237     if (r.isEmpty())
2238         return;
2239
2240     Q_D(QRasterPaintEngine);
2241     QRasterPaintEngineState *s = state();
2242     int sr_l = qFloor(sr.left());
2243     int sr_r = qCeil(sr.right()) - 1;
2244     int sr_t = qFloor(sr.top());
2245     int sr_b = qCeil(sr.bottom()) - 1;
2246
2247     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2248         // as fillRect will apply the aliased coordinate delta we need to
2249         // subtract it here as we don't use it for image drawing
2250         QTransform old = s->matrix;
2251
2252         if (s->flags.legacy_rounding)
2253             s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2254
2255         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2256         QRgb color = img.pixel(sr_l, sr_t);
2257         switch (img.format()) {
2258         case QImage::Format_ARGB32_Premultiplied:
2259         case QImage::Format_ARGB8565_Premultiplied:
2260         case QImage::Format_ARGB6666_Premultiplied:
2261         case QImage::Format_ARGB8555_Premultiplied:
2262         case QImage::Format_ARGB4444_Premultiplied:
2263             // Combine premultiplied color with the opacity set on the painter.
2264             d->solid_color_filler.solid.color =
2265                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2266                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2267             break;
2268         default:
2269             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2270             break;
2271         }
2272
2273         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2274             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2275             return;
2276         }
2277
2278         d->solid_color_filler.clip = d->clip();
2279         d->solid_color_filler.adjustSpanMethods();
2280         fillRect(r, &d->solid_color_filler);
2281
2282         s->matrix = old;
2283         return;
2284     }
2285
2286     bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
2287
2288     const QClipData *clip = d->clip();
2289
2290     if (s->matrix.type() > QTransform::TxTranslate
2291         && !stretch_sr
2292         && (!clip || clip->hasRectClip)
2293         && s->intOpacity == 256
2294         && (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
2295             || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
2296         && d->rasterBuffer->format == img.format()
2297         && (d->rasterBuffer->format == QImage::Format_RGB16
2298             || d->rasterBuffer->format == QImage::Format_RGB32
2299             || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
2300                 && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
2301     {
2302         RotationType rotationType = qRotationType(s->matrix);
2303
2304         if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
2305             QRectF transformedTargetRect = s->matrix.mapRect(r);
2306
2307             if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
2308                 || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
2309             {
2310                 QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
2311                 if (clippedTransformedTargetRect.isNull())
2312                     return;
2313
2314                 QRectF clippedTargetRect = s->matrix.inverted().mapRect(QRectF(clippedTransformedTargetRect));
2315
2316                 QRect clippedSourceRect
2317                     = QRectF(sr.x() + clippedTargetRect.x() - r.x(), sr.y() + clippedTargetRect.y() - r.y(),
2318                             clippedTargetRect.width(), clippedTargetRect.height()).toRect();
2319
2320                 uint dbpl = d->rasterBuffer->bytesPerLine();
2321                 uint sbpl = img.bytesPerLine();
2322
2323                 uchar *dst = d->rasterBuffer->buffer();
2324                 uint bpp = img.depth() >> 3;
2325
2326                 const uchar *srcBase = img.bits() + clippedSourceRect.y() * sbpl + clippedSourceRect.x() * bpp;
2327                 uchar *dstBase = dst + clippedTransformedTargetRect.y() * dbpl + clippedTransformedTargetRect.x() * bpp;
2328
2329                 uint cw = clippedSourceRect.width();
2330                 uint ch = clippedSourceRect.height();
2331
2332                 qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
2333
2334                 return;
2335             }
2336         }
2337     }
2338
2339     if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2340
2341         QRectF targetBounds = s->matrix.mapRect(r);
2342         bool exceedsPrecision = targetBounds.width() > 0xffff
2343                                 || targetBounds.height() > 0xffff;
2344
2345         if (!exceedsPrecision && d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2346             if (s->matrix.type() > QTransform::TxScale) {
2347                 SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2348                 if (func && (!clip || clip->hasRectClip)) {
2349                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2350                          img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2351                          s->matrix, s->intOpacity);
2352                     return;
2353                 }
2354             } else {
2355                 // Test for optimized high-dpi case: 2x source on 2x target. (Could be generalized to nX.)
2356                 bool sourceRect2x = r.width() * 2 == sr.width() && r.height() * 2 == sr.height();
2357                 bool scale2x = (s->matrix.m11() == qreal(2)) && (s->matrix.m22() == qreal(2));
2358                 if (s->matrix.type() == QTransform::TxScale && sourceRect2x && scale2x) {
2359                     SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2360                     if (func) {
2361                         QPointF pt(r.x() * 2 + s->matrix.dx(), r.y() * 2 + s->matrix.dy());
2362                         if (!clip) {
2363                             d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2364                             return;
2365                         } else if (clip->hasRectClip) {
2366                             d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2367                             return;
2368                         }
2369                     }
2370                 }
2371                 SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2372                 if (func && (!clip || clip->hasRectClip)) {
2373                     func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2374                          img.bits(), img.bytesPerLine(),
2375                          qt_mapRect_non_normalizing(r, s->matrix), sr,
2376                          !clip ? d->deviceRect : clip->clipRect,
2377                          s->intOpacity);
2378                     return;
2379                 }
2380             }
2381         }
2382
2383         QTransform copy = s->matrix;
2384         copy.translate(r.x(), r.y());
2385         if (stretch_sr)
2386             copy.scale(r.width() / sr.width(), r.height() / sr.height());
2387         copy.translate(-sr.x(), -sr.y());
2388
2389         d->image_filler_xform.clip = clip;
2390         d->image_filler_xform.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2391         if (!d->image_filler_xform.blend)
2392             return;
2393         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2394
2395         if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2396             QRectF rr = s->matrix.mapRect(r);
2397
2398             const int x1 = qRound(rr.x());
2399             const int y1 = qRound(rr.y());
2400             const int x2 = qRound(rr.right());
2401             const int y2 = qRound(rr.bottom());
2402
2403             fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler_xform, d);
2404             return;
2405         }
2406
2407 #ifdef QT_FAST_SPANS
2408         ensureRasterState();
2409         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2410             d->initializeRasterizer(&d->image_filler_xform);
2411             d->rasterizer->setAntialiased(s->flags.antialiased);
2412             d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
2413
2414             const QPointF offs = s->flags.legacy_rounding ? QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta) : QPointF();
2415
2416             const QRectF &rect = r.normalized();
2417             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2418             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
2419
2420             if (s->flags.tx_noshear)
2421                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2422             else
2423                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2424             return;
2425         }
2426 #endif
2427         const qreal offs = s->flags.legacy_rounding ? aliasedCoordinateDelta : qreal(0);
2428         QPainterPath path;
2429         path.addRect(r);
2430         QTransform m = s->matrix;
2431         s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
2432                                m.m21(), m.m22(), m.m23(),
2433                                m.m31() - offs, m.m32() - offs, m.m33());
2434         fillPath(path, &d->image_filler_xform);
2435         s->matrix = m;
2436     } else {
2437         if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
2438             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2439             if (func) {
2440                 QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
2441                 if (!clip) {
2442                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
2443                     return;
2444                 } else if (clip->hasRectClip) {
2445                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity, sr.toRect());
2446                     return;
2447                 }
2448             }
2449         }
2450
2451         d->image_filler.clip = clip;
2452         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, toAlignedRect_positive(sr));
2453         if (!d->image_filler.blend)
2454             return;
2455         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2456         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2457
2458         QRectF rr = r;
2459         rr.translate(s->matrix.dx(), s->matrix.dy());
2460
2461         const int x1 = qRound(rr.x());
2462         const int y1 = qRound(rr.y());
2463         const int x2 = qRound(rr.right());
2464         const int y2 = qRound(rr.bottom());
2465
2466         fillRect_normalized(QRect(x1, y1, x2-x1, y2-y1), &d->image_filler, d);
2467     }
2468 }
2469
2470 /*!
2471     \reimp
2472 */
2473 void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
2474 {
2475 #ifdef QT_DEBUG_DRAW
2476     qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
2477 #endif
2478     Q_D(QRasterPaintEngine);
2479     QRasterPaintEngineState *s = state();
2480
2481     QImage image;
2482
2483     QPlatformPixmap *pd = pixmap.handle();
2484     if (pd->classId() == QPlatformPixmap::RasterClass) {
2485         image = static_cast<QRasterPlatformPixmap *>(pd)->image;
2486     } else {
2487         image = pixmap.toImage();
2488     }
2489
2490     if (image.depth() == 1)
2491         image = d->rasterBuffer->colorizeBitmap(image, s->pen.color());
2492
2493     if (s->matrix.type() > QTransform::TxTranslate) {
2494         QTransform copy = s->matrix;
2495         copy.translate(r.x(), r.y());
2496         copy.translate(-sr.x(), -sr.y());
2497         d->image_filler_xform.clip = d->clip();
2498         d->image_filler_xform.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2499         if (!d->image_filler_xform.blend)
2500             return;
2501         d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2502
2503 #ifdef QT_FAST_SPANS
2504         ensureRasterState();
2505         if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2506             d->initializeRasterizer(&d->image_filler_xform);
2507             d->rasterizer->setAntialiased(s->flags.antialiased);
2508             d->rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
2509
2510             const QRectF &rect = r.normalized();
2511             const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2512             const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
2513             if (s->flags.tx_noshear)
2514                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
2515             else
2516                 d->rasterizer->rasterizeLine(a, b, qAbs((s->matrix.m22() * rect.height()) / (s->matrix.m11() * rect.width())));
2517             return;
2518         }
2519 #endif
2520         QPainterPath path;
2521         path.addRect(r);
2522         fillPath(path, &d->image_filler_xform);
2523     } else {
2524         d->image_filler.clip = d->clip();
2525
2526         d->image_filler.initTexture(&image, s->intOpacity, QTextureData::Tiled);
2527         if (!d->image_filler.blend)
2528             return;
2529         d->image_filler.dx = -(r.x() + s->matrix.dx()) + sr.x();
2530         d->image_filler.dy = -(r.y() + s->matrix.dy()) + sr.y();
2531
2532         QRectF rr = r;
2533         rr.translate(s->matrix.dx(), s->matrix.dy());
2534         fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
2535     }
2536 }
2537
2538
2539 //QWS hack
2540 static inline bool monoVal(const uchar* s, int x)
2541 {
2542     return  (s[x>>3] << (x&7)) & 0x80;
2543 }
2544
2545 /*!
2546     \internal
2547  */
2548 QRasterBuffer *QRasterPaintEngine::rasterBuffer()
2549 {
2550     Q_D(QRasterPaintEngine);
2551     return d->rasterBuffer.data();
2552 }
2553
2554 /*!
2555     \internal
2556 */
2557 void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
2558 {
2559     Q_D(QRasterPaintEngine);
2560     QRasterPaintEngineState *s = state();
2561
2562     if (!s->penData.blend)
2563         return;
2564
2565     QRasterBuffer *rb = d->rasterBuffer.data();
2566
2567     const QRect rect(rx, ry, w, h);
2568     const QClipData *clip = d->clip();
2569     bool unclipped = false;
2570     if (clip) {
2571         // inlined QRect::intersects
2572         const bool intersects = qMax(clip->xmin, rect.left()) <= qMin(clip->xmax - 1, rect.right())
2573                                 && qMax(clip->ymin, rect.top()) <= qMin(clip->ymax - 1, rect.bottom());
2574
2575         if (clip->hasRectClip) {
2576             unclipped = rx > clip->xmin
2577                         && rx + w < clip->xmax
2578                         && ry > clip->ymin
2579                         && ry + h < clip->ymax;
2580         }
2581
2582         if (!intersects)
2583             return;
2584     } else {
2585         // inlined QRect::intersects
2586         const bool intersects = qMax(0, rect.left()) <= qMin(rb->width() - 1, rect.right())
2587                                 && qMax(0, rect.top()) <= qMin(rb->height() - 1, rect.bottom());
2588         if (!intersects)
2589             return;
2590
2591         // inlined QRect::contains
2592         const bool contains = rect.left() >= 0 && rect.right() < rb->width()
2593                               && rect.top() >= 0 && rect.bottom() < rb->height();
2594
2595         unclipped = contains && d->isUnclipped_normalized(rect);
2596     }
2597
2598     ProcessSpans blend = unclipped ? s->penData.unclipped_blend : s->penData.blend;
2599     const uchar * scanline = static_cast<const uchar *>(src);
2600
2601     if (s->flags.fast_text) {
2602         if (unclipped) {
2603             if (depth == 1) {
2604                 if (s->penData.bitmapBlit) {
2605                     s->penData.bitmapBlit(rb, rx, ry, s->penData.solid.color,
2606                                           scanline, w, h, bpl);
2607                     return;
2608                 }
2609             } else if (depth == 8) {
2610                 if (s->penData.alphamapBlit) {
2611                     s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2612                                             scanline, w, h, bpl, 0);
2613                     return;
2614                 }
2615             } else if (depth == 32) {
2616                 // (A)RGB Alpha mask where the alpha component is not used.
2617                 if (s->penData.alphaRGBBlit) {
2618                     s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2619                                             (const uint *) scanline, w, h, bpl / 4, 0);
2620                     return;
2621                 }
2622             }
2623         } else if (d->deviceDepth == 32 && (depth == 8 || depth == 32)) {
2624             // (A)RGB Alpha mask where the alpha component is not used.
2625             if (!clip) {
2626                 int nx = qMax(0, rx);
2627                 int ny = qMax(0, ry);
2628
2629                 // Move scanline pointer to compensate for moved x and y
2630                 int xdiff = nx - rx;
2631                 int ydiff = ny - ry;
2632                 scanline += ydiff * bpl;
2633                 scanline += xdiff * (depth == 32 ? 4 : 1);
2634
2635                 w -= xdiff;
2636                 h -= ydiff;
2637
2638                 if (nx + w > d->rasterBuffer->width())
2639                     w = d->rasterBuffer->width() - nx;
2640                 if (ny + h > d->rasterBuffer->height())
2641                     h = d->rasterBuffer->height() - ny;
2642
2643                 rx = nx;
2644                 ry = ny;
2645             }
2646             if (depth == 8 && s->penData.alphamapBlit) {
2647                 s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
2648                                         scanline, w, h, bpl, clip);
2649             } else if (depth == 32 && s->penData.alphaRGBBlit) {
2650                 s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
2651                                         (const uint *) scanline, w, h, bpl / 4, clip);
2652             }
2653             return;
2654         }
2655     }
2656
2657     int x0 = 0;
2658     if (rx < 0) {
2659         x0 = -rx;
2660         w -= x0;
2661     }
2662
2663     int y0 = 0;
2664     if (ry < 0) {
2665         y0 = -ry;
2666         scanline += bpl * y0;
2667         h -= y0;
2668     }
2669
2670     w = qMin(w, rb->width() - qMax(0, rx));
2671     h = qMin(h, rb->height() - qMax(0, ry));
2672
2673     if (w <= 0 || h <= 0)
2674         return;
2675
2676     const int NSPANS = 256;
2677     QSpan spans[NSPANS];
2678     int current = 0;
2679
2680     const int x1 = x0 + w;
2681     const int y1 = y0 + h;
2682
2683     if (depth == 1) {
2684         for (int y = y0; y < y1; ++y) {
2685             for (int x = x0; x < x1; ) {
2686                 if (!monoVal(scanline, x)) {
2687                     ++x;
2688                     continue;
2689                 }
2690
2691                 if (current == NSPANS) {
2692                     blend(current, spans, &s->penData);
2693                     current = 0;
2694                 }
2695                 spans[current].x = x + rx;
2696                 spans[current].y = y + ry;
2697                 spans[current].coverage = 255;
2698                 int len = 1;
2699                 ++x;
2700                 // extend span until we find a different one.
2701                 while (x < x1 && monoVal(scanline, x)) {
2702                     ++x;
2703                     ++len;
2704                 }
2705                 spans[current].len = len;
2706                 ++current;
2707             }
2708             scanline += bpl;
2709         }
2710     } else if (depth == 8) {
2711         for (int y = y0; y < y1; ++y) {
2712             for (int x = x0; x < x1; ) {
2713                 // Skip those with 0 coverage
2714                 if (scanline[x] == 0) {
2715                     ++x;
2716                     continue;
2717                 }
2718
2719                 if (current == NSPANS) {
2720                     blend(current, spans, &s->penData);
2721                     current = 0;
2722                 }
2723                 int coverage = scanline[x];
2724                 spans[current].x = x + rx;
2725                 spans[current].y = y + ry;
2726                 spans[current].coverage = coverage;
2727                 int len = 1;
2728                 ++x;
2729
2730                 // extend span until we find a different one.
2731                 while (x < x1 && scanline[x] == coverage) {
2732                     ++x;
2733                     ++len;
2734                 }
2735                 spans[current].len = len;
2736                 ++current;
2737             }
2738             scanline += bpl;
2739         }
2740     } else { // 32-bit alpha...
2741         uint *sl = (uint *) src;
2742         for (int y = y0; y < y1; ++y) {
2743             for (int x = x0; x < x1; ) {
2744                 // Skip those with 0 coverage
2745                 if ((sl[x] & 0x00ffffff) == 0) {
2746                     ++x;
2747                     continue;
2748                 }
2749
2750                 if (current == NSPANS) {
2751                     blend(current, spans, &s->penData);
2752                     current = 0;
2753                 }
2754                 uint rgbCoverage = sl[x];
2755                 int coverage = qGreen(rgbCoverage);
2756                 spans[current].x = x + rx;
2757                 spans[current].y = y + ry;
2758                 spans[current].coverage = coverage;
2759                 int len = 1;
2760                 ++x;
2761
2762                 // extend span until we find a different one.
2763                 while (x < x1 && sl[x] == rgbCoverage) {
2764                     ++x;
2765                     ++len;
2766                 }
2767                 spans[current].len = len;
2768                 ++current;
2769             }
2770             sl += bpl / sizeof(uint);
2771         }
2772     }
2773 //     qDebug() << "alphaPenBlt: num spans=" << current
2774 //              << "span:" << spans->x << spans->y << spans->len << spans->coverage;
2775         // Call span func for current set of spans.
2776     if (current != 0)
2777         blend(current, spans, &s->penData);
2778 }
2779
2780 /*!
2781     \internal
2782 */
2783 bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
2784                                           const QFixedPoint *positions, QFontEngine *fontEngine)
2785 {
2786     Q_D(QRasterPaintEngine);
2787     QRasterPaintEngineState *s = state();
2788
2789     if (fontEngine->hasInternalCaching()) {
2790         QFontEngine::GlyphFormat neededFormat =
2791             painter()->device()->devType() == QInternal::Widget
2792             ? QFontEngine::Format_None
2793             : QFontEngine::Format_A8;
2794
2795         if (d_func()->mono_surface) // alphaPenBlt can handle mono, too
2796             neededFormat = QFontEngine::Format_Mono;
2797
2798         for (int i = 0; i < numGlyphs; i++) {
2799             QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);
2800
2801             QPoint offset;
2802             QImage *alphaMap = fontEngine->lockedAlphaMapForGlyph(glyphs[i], spp, neededFormat, s->matrix,
2803                                                                   &offset);
2804             if (alphaMap == 0 || alphaMap->isNull())
2805                 continue;
2806
2807             alphaPenBlt(alphaMap->bits(), alphaMap->bytesPerLine(), alphaMap->depth(),
2808                         qFloor(positions[i].x) + offset.x(),
2809                         qRound(positions[i].y) + offset.y(),
2810                         alphaMap->width(), alphaMap->height());
2811
2812             fontEngine->unlockAlphaMapForGlyph();
2813         }
2814
2815     } else {
2816         QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
2817
2818         QImageTextureGlyphCache *cache =
2819             static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
2820         if (!cache) {
2821             cache = new QImageTextureGlyphCache(glyphType, s->matrix);
2822             fontEngine->setGlyphCache(0, cache);
2823         }
2824
2825         cache->populate(fontEngine, numGlyphs, glyphs, positions);
2826         cache->fillInPendingGlyphs();
2827
2828         const QImage &image = cache->image();
2829         int bpl = image.bytesPerLine();
2830
2831         int depth = image.depth();
2832         int rightShift = 0;
2833         int leftShift = 0;
2834         if (depth == 32)
2835             leftShift = 2; // multiply by 4
2836         else if (depth == 1)
2837             rightShift = 3; // divide by 8
2838
2839         int margin = fontEngine->glyphMargin(glyphType);
2840         const uchar *bits = image.bits();
2841         for (int i=0; i<numGlyphs; ++i) {
2842
2843             QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
2844             QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
2845             const QTextureGlyphCache::Coord &c = cache->coords[glyph];
2846             if (c.isNull())
2847                 continue;
2848
2849             int x = qFloor(positions[i].x) + c.baseLineX - margin;
2850             int y = qRound(positions[i].y) - c.baseLineY - margin;
2851
2852             // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
2853             //        c.x, c.y,
2854             //        c.w, c.h,
2855             //        c.baseLineX, c.baseLineY,
2856             //        glyphs[i],
2857             //        x, y,
2858             //        positions[i].x.toInt(), positions[i].y.toInt());
2859
2860             alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
2861         }
2862     }
2863     return true;
2864 }
2865
2866
2867 /*!
2868  * Returns true if the rectangle is completely within the current clip
2869  * state of the paint engine.
2870  */
2871 bool QRasterPaintEnginePrivate::isUnclipped_normalized(const QRect &r) const
2872 {
2873     const QClipData *cl = clip();
2874     if (!cl) {
2875         // inline contains() for performance (we know the rects are normalized)
2876         const QRect &r1 = deviceRect;
2877         return (r.left() >= r1.left() && r.right() <= r1.right()
2878                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2879     }
2880
2881
2882     if (cl->hasRectClip) {
2883         // currently all painting functions clips to deviceRect internally
2884         if (cl->clipRect == deviceRect)
2885             return true;
2886
2887         // inline contains() for performance (we know the rects are normalized)
2888         const QRect &r1 = cl->clipRect;
2889         return (r.left() >= r1.left() && r.right() <= r1.right()
2890                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2891     } else {
2892         return qt_region_strictContains(cl->clipRegion, r);
2893     }
2894 }
2895
2896 bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
2897                                             int penWidth) const
2898 {
2899     Q_Q(const QRasterPaintEngine);
2900     const QRasterPaintEngineState *s = q->state();
2901     const QClipData *cl = clip();
2902     if (!cl) {
2903         QRect r = rect.normalized();
2904         // inline contains() for performance (we know the rects are normalized)
2905         const QRect &r1 = deviceRect;
2906         return (r.left() >= r1.left() && r.right() <= r1.right()
2907                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2908     }
2909
2910
2911     // currently all painting functions that call this function clip to deviceRect internally
2912     if (cl->hasRectClip && cl->clipRect == deviceRect)
2913         return true;
2914
2915     if (s->flags.antialiased)
2916         ++penWidth;
2917
2918     QRect r = rect.normalized();
2919     if (penWidth > 0) {
2920         r.setX(r.x() - penWidth);
2921         r.setY(r.y() - penWidth);
2922         r.setWidth(r.width() + 2 * penWidth);
2923         r.setHeight(r.height() + 2 * penWidth);
2924     }
2925
2926     if (cl->hasRectClip) {
2927         // inline contains() for performance (we know the rects are normalized)
2928         const QRect &r1 = cl->clipRect;
2929         return (r.left() >= r1.left() && r.right() <= r1.right()
2930                 && r.top() >= r1.top() && r.bottom() <= r1.bottom());
2931     } else {
2932         return qt_region_strictContains(cl->clipRegion, r);
2933     }
2934 }
2935
2936 inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
2937                                                    int penWidth) const
2938 {
2939     return isUnclipped(rect.normalized().toAlignedRect(), penWidth);
2940 }
2941
2942 inline ProcessSpans
2943 QRasterPaintEnginePrivate::getBrushFunc(const QRect &rect,
2944                                         const QSpanData *data) const
2945 {
2946     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2947 }
2948
2949 inline ProcessSpans
2950 QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
2951                                         const QSpanData *data) const
2952 {
2953     return isUnclipped(rect, 0) ? data->unclipped_blend : data->blend;
2954 }
2955
2956 inline ProcessSpans
2957 QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
2958                                       const QSpanData *data) const
2959 {
2960     Q_Q(const QRasterPaintEngine);
2961     const QRasterPaintEngineState *s = q->state();
2962
2963     if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
2964         return data->blend;
2965     const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->lastPen.widthF());
2966     return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
2967 }
2968
2969 static QPair<int, int> visibleGlyphRange(const QRectF &clip, QFontEngine *fontEngine,
2970                                          glyph_t *glyphs, QFixedPoint *positions, int numGlyphs)
2971 {
2972     QFixed clipLeft = QFixed::fromReal(clip.left());
2973     QFixed clipRight = QFixed::fromReal(clip.right());
2974     QFixed clipTop = QFixed::fromReal(clip.top());
2975     QFixed clipBottom = QFixed::fromReal(clip.bottom());
2976
2977     int first = 0;
2978     while (first < numGlyphs) {
2979         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[first]);
2980         QFixed left = metrics.x + positions[first].x;
2981         QFixed top = metrics.y + positions[first].y;
2982         QFixed right = left + metrics.width;
2983         QFixed bottom = top + metrics.height;
2984         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2985             break;
2986         ++first;
2987     }
2988     int last = numGlyphs - 1;
2989     while (last > first) {
2990         glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[last]);
2991         QFixed left = metrics.x + positions[last].x;
2992         QFixed top = metrics.y + positions[last].y;
2993         QFixed right = left + metrics.width;
2994         QFixed bottom = top + metrics.height;
2995         if (left < clipRight && right > clipLeft && top < clipBottom && bottom > clipTop)
2996             break;
2997         --last;
2998     }
2999     return QPair<int, int>(first, last + 1);
3000 }
3001
3002 /*!
3003    \reimp
3004 */
3005 void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
3006 {
3007     if (textItem->numGlyphs == 0)
3008         return;
3009
3010     ensurePen();
3011     ensureRasterState();
3012
3013     QFontEngine *fontEngine = textItem->fontEngine();
3014     if (!supportsTransformations(fontEngine)) {
3015         drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
3016                          fontEngine);
3017     } else if (state()->matrix.type() < QTransform::TxProject) {
3018         bool invertible;
3019         QTransform invMat = state()->matrix.inverted(&invertible);
3020         if (!invertible)
3021             return;
3022
3023         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3024                                                   textItem->fontEngine(), textItem->glyphs,
3025                                                   textItem->glyphPositions, textItem->numGlyphs);
3026         QStaticTextItem copy = *textItem;
3027         copy.glyphs += range.first;
3028         copy.glyphPositions += range.first;
3029         copy.numGlyphs = range.second - range.first;
3030         QPaintEngineEx::drawStaticTextItem(&copy);
3031     } else {
3032         QPaintEngineEx::drawStaticTextItem(textItem);
3033     }
3034 }
3035
3036 /*!
3037     \reimp
3038 */
3039 void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
3040 {
3041     const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
3042
3043 #ifdef QT_DEBUG_DRAW
3044     Q_D(QRasterPaintEngine);
3045     fprintf(stderr," - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s ct=%d\n",
3046            p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data(),
3047            d->glyphCacheType);
3048 #endif
3049
3050     if (ti.glyphs.numGlyphs == 0)
3051         return;
3052     ensurePen();
3053     ensureRasterState();
3054
3055     QRasterPaintEngineState *s = state();
3056     QTransform matrix = s->matrix;
3057
3058     if (!supportsTransformations(ti.fontEngine)) {
3059         QVarLengthArray<QFixedPoint> positions;
3060         QVarLengthArray<glyph_t> glyphs;
3061
3062         matrix.translate(p.x(), p.y());
3063         ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3064
3065         drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
3066     } else if (matrix.type() < QTransform::TxProject) {
3067         bool invertible;
3068         QTransform invMat = matrix.inverted(&invertible);
3069         if (!invertible)
3070             return;
3071
3072         QVarLengthArray<QFixedPoint> positions;
3073         QVarLengthArray<glyph_t> glyphs;
3074
3075         ti.fontEngine->getGlyphPositions(ti.glyphs, QTransform::fromTranslate(p.x(), p.y()),
3076                                          ti.flags, glyphs, positions);
3077         QPair<int, int> range = visibleGlyphRange(invMat.mapRect(clipBoundingRect()),
3078                                                   ti.fontEngine, glyphs.data(), positions.data(),
3079                                                   glyphs.size());
3080
3081         if (range.first >= range.second)
3082             return;
3083
3084         QStaticTextItem staticTextItem;
3085         staticTextItem.color = s->pen.color();
3086         staticTextItem.font = s->font;
3087         staticTextItem.setFontEngine(ti.fontEngine);
3088         staticTextItem.numGlyphs = range.second - range.first;
3089         staticTextItem.glyphs = glyphs.data() + range.first;
3090         staticTextItem.glyphPositions = positions.data() + range.first;
3091         QPaintEngineEx::drawStaticTextItem(&staticTextItem);
3092     } else {
3093         QPaintEngineEx::drawTextItem(p, ti);
3094     }
3095 }
3096
3097 /*!
3098     \reimp
3099 */
3100 void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
3101 {
3102     Q_D(QRasterPaintEngine);
3103     QRasterPaintEngineState *s = state();
3104
3105     ensurePen();
3106     if (!s->penData.blend)
3107         return;
3108
3109     if (!s->flags.fast_pen) {
3110         QPaintEngineEx::drawPoints(points, pointCount);
3111         return;
3112     }
3113
3114     QCosmeticStroker stroker(s, d->deviceRect);
3115     stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3116     stroker.drawPoints(points, pointCount);
3117 }
3118
3119
3120 void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
3121 {
3122     Q_D(QRasterPaintEngine);
3123     QRasterPaintEngineState *s = state();
3124
3125     ensurePen();
3126     if (!s->penData.blend)
3127         return;
3128
3129     if (!s->flags.fast_pen) {
3130         QPaintEngineEx::drawPoints(points, pointCount);
3131         return;
3132     }
3133
3134     QCosmeticStroker stroker(s, d->deviceRect);
3135     stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3136     stroker.drawPoints(points, pointCount);
3137 }
3138
3139 /*!
3140     \reimp
3141 */
3142 void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
3143 {
3144 #ifdef QT_DEBUG_DRAW
3145     qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
3146 #endif
3147     Q_D(QRasterPaintEngine);
3148     QRasterPaintEngineState *s = state();
3149
3150     ensurePen();
3151     if (!s->penData.blend)
3152         return;
3153
3154     if (s->flags.fast_pen) {
3155         QCosmeticStroker stroker(s, d->deviceRect);
3156         stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3157         for (int i=0; i<lineCount; ++i) {
3158             const QLine &l = lines[i];
3159             stroker.drawLine(l.p1(), l.p2());
3160         }
3161     } else {
3162         QPaintEngineEx::drawLines(lines, lineCount);
3163     }
3164 }
3165
3166 void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
3167                                                      qreal width,
3168                                                      int *dashIndex,
3169                                                      qreal *dashOffset,
3170                                                      bool *inDash)
3171 {
3172     Q_Q(QRasterPaintEngine);
3173     QRasterPaintEngineState *s = q->state();
3174
3175     const QPen &pen = s->lastPen;
3176     const bool squareCap = (pen.capStyle() == Qt::SquareCap);
3177     const QVector<qreal> pattern = pen.dashPattern();
3178
3179     qreal patternLength = 0;
3180     for (int i = 0; i < pattern.size(); ++i)
3181         patternLength += pattern.at(i);
3182
3183     if (patternLength <= 0)
3184         return;
3185
3186     qreal length = line.length();
3187     Q_ASSERT(length > 0);
3188     while (length > 0) {
3189         const bool rasterize = *inDash;
3190         qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
3191         QLineF l = line;
3192
3193         if (dash >= length) {
3194             dash = length;
3195             *dashOffset += dash / width;
3196             length = 0;
3197         } else {
3198             *dashOffset = 0;
3199             *inDash = !(*inDash);
3200             if (++*dashIndex >= pattern.size())
3201                 *dashIndex = 0;
3202             length -= dash;
3203             l.setLength(dash);
3204             line.setP1(l.p2());
3205         }
3206
3207         if (rasterize && dash > 0)
3208             rasterizer->rasterizeLine(l.p1(), l.p2(), width / dash, squareCap);
3209     }
3210 }
3211
3212 /*!
3213     \reimp
3214 */
3215 void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
3216 {
3217 #ifdef QT_DEBUG_DRAW
3218     qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
3219 #endif
3220     Q_D(QRasterPaintEngine);
3221     QRasterPaintEngineState *s = state();
3222
3223     ensurePen();
3224     if (!s->penData.blend)
3225         return;
3226     if (s->flags.fast_pen) {
3227         QCosmeticStroker stroker(s, d->deviceRect);
3228         stroker.setLegacyRoundingEnabled(s->flags.legacy_rounding);
3229         for (int i=0; i<lineCount; ++i) {
3230             QLineF line = lines[i];
3231             stroker.drawLine(line.p1(), line.p2());
3232         }
3233     } else {
3234         QPaintEngineEx::drawLines(lines, lineCount);
3235     }
3236 }
3237
3238
3239 /*!
3240     \reimp
3241 */
3242 void QRasterPaintEngine::drawEllipse(const QRectF &rect)
3243 {
3244     Q_D(QRasterPaintEngine);
3245     QRasterPaintEngineState *s = state();
3246
3247     ensurePen();
3248     if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3249            || (qpen_style(s->lastPen) == Qt::NoPen))
3250         && !s->flags.antialiased
3251         && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3252         && !rect.isEmpty()
3253         && s->matrix.type() <= QTransform::TxScale) // no shear
3254     {
3255         ensureBrush();
3256         const QRectF r = s->matrix.mapRect(rect);
3257         ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
3258         ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
3259         const QRect brect = QRect(int(r.x()), int(r.y()),
3260                                   int_dim(r.x(), r.width()),
3261                                   int_dim(r.y(), r.height()));
3262         if (brect == r) {
3263             drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
3264                                    &s->penData, &s->brushData);
3265             return;
3266         }
3267     }
3268     QPaintEngineEx::drawEllipse(rect);
3269 }
3270
3271
3272 #ifdef Q_OS_WIN
3273 /*!
3274     \internal
3275 */
3276 void QRasterPaintEngine::setDC(HDC hdc) {
3277     Q_D(QRasterPaintEngine);
3278     d->hdc = hdc;
3279 }
3280
3281 /*!
3282     \internal
3283 */
3284 HDC QRasterPaintEngine::getDC() const
3285 {
3286     Q_D(const QRasterPaintEngine);
3287     return d->hdc;
3288 }
3289
3290 /*!
3291     \internal
3292 */
3293 void QRasterPaintEngine::releaseDC(HDC) const
3294 {
3295 }
3296
3297 #endif
3298
3299 /*!
3300     \internal
3301 */
3302 bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const
3303 {
3304     const QTransform &m = state()->matrix;
3305     return supportsTransformations(fontEngine, m);
3306 }
3307
3308 /*!
3309     \internal
3310 */
3311 bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const
3312 {
3313     if (fontEngine->supportsTransformations(m))
3314         return true;
3315
3316     return !shouldDrawCachedGlyphs(fontEngine, m);
3317 }
3318
3319 /*!
3320     \internal
3321 */
3322 QPoint QRasterPaintEngine::coordinateOffset() const
3323 {
3324     return QPoint(0, 0);
3325 }
3326
3327 void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fg)
3328 {
3329     Q_ASSERT(fg);
3330     if (!fg->blend)
3331         return;
3332     Q_D(QRasterPaintEngine);
3333
3334     Q_ASSERT(image.depth() == 1);
3335
3336     const int spanCount = 256;
3337     QT_FT_Span spans[spanCount];
3338     int n = 0;
3339
3340     // Boundaries
3341     int w = image.width();
3342     int h = image.height();
3343     int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
3344     int ymin = qMax(qRound(pos.y()), 0);
3345     int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
3346     int xmin = qMax(qRound(pos.x()), 0);
3347
3348     int x_offset = xmin - qRound(pos.x());
3349
3350     QImage::Format format = image.format();
3351     for (int y = ymin; y < ymax; ++y) {
3352         const uchar *src = image.scanLine(y - qRound(pos.y()));
3353         if (format == QImage::Format_MonoLSB) {
3354             for (int x = 0; x < xmax - xmin; ++x) {
3355                 int src_x = x + x_offset;
3356                 uchar pixel = src[src_x >> 3];
3357                 if (!pixel) {
3358                     x += 7 - (src_x%8);
3359                     continue;
3360                 }
3361                 if (pixel & (0x1 << (src_x & 7))) {
3362                     spans[n].x = xmin + x;
3363                     spans[n].y = y;
3364                     spans[n].coverage = 255;
3365                     int len = 1;
3366                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
3367                         ++src_x;
3368                         ++len;
3369                     }
3370                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3371                     x += len;
3372                     ++n;
3373                     if (n == spanCount) {
3374                         fg->blend(n, spans, fg);
3375                         n = 0;
3376                     }
3377                 }
3378             }
3379         } else {
3380             for (int x = 0; x < xmax - xmin; ++x) {
3381                 int src_x = x + x_offset;
3382                 uchar pixel = src[src_x >> 3];
3383                 if (!pixel) {
3384                     x += 7 - (src_x%8);
3385                     continue;
3386                 }
3387                 if (pixel & (0x80 >> (x & 7))) {
3388                     spans[n].x = xmin + x;
3389                     spans[n].y = y;
3390                     spans[n].coverage = 255;
3391                     int len = 1;
3392                     while (src_x+1 < w && src[(src_x+1) >> 3] & (0x80 >> ((src_x+1) & 7))) {
3393                         ++src_x;
3394                         ++len;
3395                     }
3396                     spans[n].len = ((len + spans[n].x) > xmax) ? (xmax - spans[n].x) : len;
3397                     x += len;
3398                     ++n;
3399                     if (n == spanCount) {
3400                         fg->blend(n, spans, fg);
3401                         n = 0;
3402                     }
3403                 }
3404             }
3405         }
3406     }
3407     if (n) {
3408         fg->blend(n, spans, fg);
3409         n = 0;
3410     }
3411 }
3412
3413 /*!
3414     \enum QRasterPaintEngine::ClipType
3415     \internal
3416
3417     \value RectClip Indicates that the currently set clip is a single rectangle.
3418     \value ComplexClip Indicates that the currently set clip is a combination of several shapes.
3419 */
3420
3421 /*!
3422     \internal
3423     Returns the type of the clip currently set.
3424 */
3425 QRasterPaintEngine::ClipType QRasterPaintEngine::clipType() const
3426 {
3427     Q_D(const QRasterPaintEngine);
3428
3429     const QClipData *clip = d->clip();
3430     if (!clip || clip->hasRectClip)
3431         return RectClip;
3432     else
3433         return ComplexClip;
3434 }
3435
3436 /*!
3437     \internal
3438     Returns the bounding rect of the currently set clip.
3439 */
3440 QRect QRasterPaintEngine::clipBoundingRect() const
3441 {
3442     Q_D(const QRasterPaintEngine);
3443
3444     const QClipData *clip = d->clip();
3445
3446     if (!clip)
3447         return d->deviceRect;
3448
3449     if (clip->hasRectClip)
3450         return clip->clipRect;
3451
3452     return QRect(clip->xmin, clip->ymin, clip->xmax - clip->xmin, clip->ymax - clip->ymin);
3453 }
3454
3455 void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3456 {
3457     Q_Q(QRasterPaintEngine);
3458     QRasterPaintEngineState *s = q->state();
3459
3460     rasterizer->setAntialiased(s->flags.antialiased);
3461     rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
3462
3463     QRect clipRect(deviceRect);
3464     ProcessSpans blend;
3465     // ### get from optimized rectbased QClipData
3466
3467     const QClipData *c = clip();
3468     if (c) {
3469         const QRect r(QPoint(c->xmin, c->ymin),
3470                       QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3471         clipRect = clipRect.intersected(r);
3472         blend = data->blend;
3473     } else {
3474         blend = data->unclipped_blend;
3475     }
3476
3477     rasterizer->setClipRect(clipRect);
3478     rasterizer->initialize(blend, data);
3479 }
3480
3481 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3482                                           ProcessSpans callback,
3483                                           QSpanData *spanData, QRasterBuffer *rasterBuffer)
3484 {
3485     if (!callback || !outline)
3486         return;
3487
3488     Q_Q(QRasterPaintEngine);
3489     QRasterPaintEngineState *s = q->state();
3490
3491     if (!s->flags.antialiased) {
3492         initializeRasterizer(spanData);
3493
3494         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3495                                       ? Qt::WindingFill
3496                                       : Qt::OddEvenFill;
3497
3498         rasterizer->rasterize(outline, fillRule);
3499         return;
3500     }
3501
3502     rasterize(outline, callback, (void *)spanData, rasterBuffer);
3503 }
3504
3505 extern "C" {
3506     int q_gray_rendered_spans(QT_FT_Raster raster);
3507 }
3508
3509 static inline uchar *alignAddress(uchar *address, quintptr alignmentMask)
3510 {
3511     return (uchar *)(((quintptr)address + alignmentMask) & ~alignmentMask);
3512 }
3513
3514 void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline,
3515                                           ProcessSpans callback,
3516                                           void *userData, QRasterBuffer *)
3517 {
3518     if (!callback || !outline)
3519         return;
3520
3521     Q_Q(QRasterPaintEngine);
3522     QRasterPaintEngineState *s = q->state();
3523
3524     if (!s->flags.antialiased) {
3525         rasterizer->setAntialiased(s->flags.antialiased);
3526         rasterizer->setLegacyRoundingEnabled(s->flags.legacy_rounding);
3527         rasterizer->setClipRect(deviceRect);
3528         rasterizer->initialize(callback, userData);
3529
3530         const Qt::FillRule fillRule = outline->flags == QT_FT_OUTLINE_NONE
3531                                       ? Qt::WindingFill
3532                                       : Qt::OddEvenFill;
3533
3534         rasterizer->rasterize(outline, fillRule);
3535         return;
3536     }
3537
3538     // Initial size for raster pool is MINIMUM_POOL_SIZE so as to
3539     // minimize memory reallocations. However if initial size for
3540     // raster pool is changed for lower value, reallocations will
3541     // occur normally.
3542     int rasterPoolSize = MINIMUM_POOL_SIZE;
3543     uchar rasterPoolOnStack[MINIMUM_POOL_SIZE + 0xf];
3544     uchar *rasterPoolBase = alignAddress(rasterPoolOnStack, 0xf);
3545     uchar *rasterPoolOnHeap = 0;
3546
3547     qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3548
3549     void *data = userData;
3550
3551     QT_FT_BBox clip_box = { deviceRect.x(),
3552                             deviceRect.y(),
3553                             deviceRect.x() + deviceRect.width(),
3554                             deviceRect.y() + deviceRect.height() };
3555
3556     QT_FT_Raster_Params rasterParams;
3557     rasterParams.target = 0;
3558     rasterParams.source = outline;
3559     rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
3560     rasterParams.gray_spans = 0;
3561     rasterParams.black_spans = 0;
3562     rasterParams.bit_test = 0;
3563     rasterParams.bit_set = 0;
3564     rasterParams.user = data;
3565     rasterParams.clip_box = clip_box;
3566
3567     bool done = false;
3568     int error;
3569
3570     int rendered_spans = 0;
3571
3572     while (!done) {
3573
3574         rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
3575         rasterParams.gray_spans = callback;
3576         rasterParams.skip_spans = rendered_spans;
3577         error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
3578
3579         // Out of memory, reallocate some more and try again...
3580         if (error == -6) { // ErrRaster_OutOfMemory from qgrayraster.c
3581             rasterPoolSize *= 2;
3582             if (rasterPoolSize > 1024 * 1024) {
3583                 qWarning("QPainter: Rasterization of primitive failed");
3584                 break;
3585             }
3586
3587             rendered_spans += q_gray_rendered_spans(*grayRaster.data());
3588
3589             free(rasterPoolOnHeap);
3590             rasterPoolOnHeap = (uchar *)malloc(rasterPoolSize + 0xf);
3591
3592             Q_CHECK_PTR(rasterPoolOnHeap); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
3593
3594             rasterPoolBase = alignAddress(rasterPoolOnHeap, 0xf);
3595
3596             qt_ft_grays_raster.raster_done(*grayRaster.data());
3597             qt_ft_grays_raster.raster_new(grayRaster.data());
3598             qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
3599         } else {
3600             done = true;
3601         }
3602     }
3603
3604     free(rasterPoolOnHeap);
3605 }
3606
3607 void QRasterPaintEnginePrivate::recalculateFastImages()
3608 {
3609     Q_Q(QRasterPaintEngine);
3610     QRasterPaintEngineState *s = q->state();
3611
3612     s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
3613                            && s->matrix.type() <= QTransform::TxShear;
3614 }
3615
3616 bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const
3617 {
3618     Q_Q(const QRasterPaintEngine);
3619     const QRasterPaintEngineState *s = q->state();
3620
3621     return s->flags.fast_images
3622            && (mode == QPainter::CompositionMode_SourceOver
3623                || (mode == QPainter::CompositionMode_Source
3624                    && !image.hasAlphaChannel()));
3625 }
3626
3627 QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
3628 {
3629     Q_ASSERT(image.depth() == 1);
3630
3631     QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
3632     QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
3633
3634     QRgb fg = PREMUL(color.rgba());
3635     QRgb bg = 0;
3636
3637     int height = sourceImage.height();
3638     int width = sourceImage.width();
3639     for (int y=0; y<height; ++y) {
3640         uchar *source = sourceImage.scanLine(y);
3641         QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
3642         if (!source || !target)
3643             QT_THROW(std::bad_alloc()); // we must have run out of memory
3644         for (int x=0; x < width; ++x)
3645             target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
3646     }
3647     return dest;
3648 }
3649
3650 QRasterBuffer::~QRasterBuffer()
3651 {
3652 }
3653
3654 void QRasterBuffer::init()
3655 {
3656     compositionMode = QPainter::CompositionMode_SourceOver;
3657     monoDestinationWithClut = false;
3658     destColor0 = 0;
3659     destColor1 = 0;
3660 }
3661
3662 QImage::Format QRasterBuffer::prepare(QImage *image)
3663 {
3664     m_buffer = (uchar *)image->bits();
3665     m_width = qMin(QT_RASTER_COORD_LIMIT, image->width());
3666     m_height = qMin(QT_RASTER_COORD_LIMIT, image->height());
3667     bytes_per_pixel = image->depth()/8;
3668     bytes_per_line = image->bytesPerLine();
3669
3670     format = image->format();
3671     drawHelper = qDrawHelper + format;
3672     if (image->depth() == 1 && image->colorTable().size() == 2) {
3673         monoDestinationWithClut = true;
3674         destColor0 = PREMUL(image->colorTable()[0]);
3675         destColor1 = PREMUL(image->colorTable()[1]);
3676     }
3677
3678     return format;
3679 }
3680
3681 void QRasterBuffer::resetBuffer(int val)
3682 {
3683     memset(m_buffer, val, m_height*bytes_per_line);
3684 }
3685
3686 QClipData::QClipData(int height)
3687 {
3688     clipSpanHeight = height;
3689     m_clipLines = 0;
3690
3691     allocated = 0;
3692     m_spans = 0;
3693     xmin = xmax = ymin = ymax = 0;
3694     count = 0;
3695
3696     enabled = true;
3697     hasRectClip = hasRegionClip = false;
3698 }
3699
3700 QClipData::~QClipData()
3701 {
3702     if (m_clipLines)
3703         free(m_clipLines);
3704     if (m_spans)
3705         free(m_spans);
3706 }
3707
3708 void QClipData::initialize()
3709 {
3710     if (m_spans)
3711         return;
3712
3713     if (!m_clipLines)
3714         m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
3715
3716     Q_CHECK_PTR(m_clipLines);
3717     QT_TRY {
3718         m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
3719         allocated = clipSpanHeight;
3720         Q_CHECK_PTR(m_spans);
3721
3722         QT_TRY {
3723             if (hasRectClip) {
3724                 int y = 0;
3725                 while (y < ymin) {
3726                     m_clipLines[y].spans = 0;
3727                     m_clipLines[y].count = 0;
3728                     ++y;
3729                 }
3730
3731                 const int len = clipRect.width();
3732                 count = 0;
3733                 while (y < ymax) {
3734                     QSpan *span = m_spans + count;
3735                     span->x = xmin;
3736                     span->len = len;
3737                     span->y = y;
3738                     span->coverage = 255;
3739                     ++count;
3740
3741                     m_clipLines[y].spans = span;
3742                     m_clipLines[y].count = 1;
3743                     ++y;
3744                 }
3745
3746                 while (y < clipSpanHeight) {
3747                     m_clipLines[y].spans = 0;
3748                     m_clipLines[y].count = 0;
3749                     ++y;
3750                 }
3751             } else if (hasRegionClip) {
3752
3753                 const QVector<QRect> rects = clipRegion.rects();
3754                 const int numRects = rects.size();
3755
3756                 { // resize
3757                     const int maxSpans = (ymax - ymin) * numRects;
3758                     if (maxSpans > allocated) {
3759                         m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
3760                         allocated = maxSpans;
3761                     }
3762                 }
3763
3764                 int y = 0;
3765                 int firstInBand = 0;
3766                 count = 0;
3767                 while (firstInBand < numRects) {
3768                     const int currMinY = rects.at(firstInBand).y();
3769                     const int currMaxY = currMinY + rects.at(firstInBand).height();
3770
3771                     while (y < currMinY) {
3772                         m_clipLines[y].spans = 0;
3773                         m_clipLines[y].count = 0;
3774                         ++y;
3775                     }
3776
3777                     int lastInBand = firstInBand;
3778                     while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
3779                         ++lastInBand;
3780
3781                     while (y < currMaxY) {
3782
3783                         m_clipLines[y].spans = m_spans + count;
3784                         m_clipLines[y].count = lastInBand - firstInBand + 1;
3785
3786                         for (int r = firstInBand; r <= lastInBand; ++r) {
3787                             const QRect &currRect = rects.at(r);
3788                             QSpan *span = m_spans + count;
3789                             span->x = currRect.x();
3790                             span->len = currRect.width();
3791                             span->y = y;
3792                             span->coverage = 255;
3793                             ++count;
3794                         }
3795                         ++y;
3796                     }
3797
3798                     firstInBand = lastInBand + 1;
3799                 }
3800
3801                 Q_ASSERT(count <= allocated);
3802
3803                 while (y < clipSpanHeight) {
3804                     m_clipLines[y].spans = 0;
3805                     m_clipLines[y].count = 0;
3806                     ++y;
3807                 }
3808
3809             }
3810         } QT_CATCH(...) {
3811             free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
3812             m_spans = 0;
3813             QT_RETHROW;
3814         }
3815     } QT_CATCH(...) {
3816         free(m_clipLines); // same for clipLines
3817         m_clipLines = 0;
3818         QT_RETHROW;
3819     }
3820 }
3821
3822 void QClipData::fixup()
3823 {
3824     Q_ASSERT(m_spans);
3825
3826     if (count == 0) {
3827         ymin = ymax = xmin = xmax = 0;
3828         return;
3829     }
3830
3831     int y = -1;
3832     ymin = m_spans[0].y;
3833     ymax = m_spans[count-1].y + 1;
3834     xmin = INT_MAX;
3835     xmax = 0;
3836
3837     const int firstLeft = m_spans[0].x;
3838     const int firstRight = m_spans[0].x + m_spans[0].len;
3839     bool isRect = true;
3840
3841     for (int i = 0; i < count; ++i) {
3842         QT_FT_Span_& span = m_spans[i];
3843
3844         if (span.y != y) {
3845             if (span.y != y + 1 && y != -1)
3846                 isRect = false;
3847             y = span.y;
3848             m_clipLines[y].spans = &span;
3849             m_clipLines[y].count = 1;
3850         } else
3851             ++m_clipLines[y].count;
3852
3853         const int spanLeft = span.x;
3854         const int spanRight = spanLeft + span.len;
3855
3856         if (spanLeft < xmin)
3857             xmin = spanLeft;
3858
3859         if (spanRight > xmax)
3860             xmax = spanRight;
3861
3862         if (spanLeft != firstLeft || spanRight != firstRight)
3863             isRect = false;
3864     }
3865
3866     if (isRect) {
3867         hasRectClip = true;
3868         clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
3869     }
3870 }
3871
3872 /*
3873     Convert \a rect to clip spans.
3874  */
3875 void QClipData::setClipRect(const QRect &rect)
3876 {
3877     if (hasRectClip && rect == clipRect)
3878         return;
3879
3880 //    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
3881     hasRectClip = true;
3882     hasRegionClip = false;
3883     clipRect = rect;
3884
3885     xmin = rect.x();
3886     xmax = rect.x() + rect.width();
3887     ymin = qMin(rect.y(), clipSpanHeight);
3888     ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
3889
3890     if (m_spans) {
3891         free(m_spans);
3892         m_spans = 0;
3893     }
3894
3895 //    qDebug() << xmin << xmax << ymin << ymax;
3896 }
3897
3898 /*
3899     Convert \a region to clip spans.
3900  */
3901 void QClipData::setClipRegion(const QRegion &region)
3902 {
3903     if (region.rectCount() == 1) {
3904         setClipRect(region.rects().at(0));
3905         return;
3906     }
3907
3908     hasRegionClip = true;
3909     hasRectClip = false;
3910     clipRegion = region;
3911
3912     { // set bounding rect
3913         const QRect rect = region.boundingRect();
3914         xmin = rect.x();
3915         xmax = rect.x() + rect.width();
3916         ymin = rect.y();
3917         ymax = rect.y() + rect.height();
3918     }
3919
3920     if (m_spans) {
3921         free(m_spans);
3922         m_spans = 0;
3923     }
3924
3925 }
3926
3927 /*!
3928     \internal
3929     spans must be sorted on y
3930 */
3931 static const QSpan *qt_intersect_spans(const QClipData *clip, int *currentClip,
3932                                        const QSpan *spans, const QSpan *end,
3933                                        QSpan **outSpans, int available)
3934 {
3935     const_cast<QClipData *>(clip)->initialize();
3936
3937     QSpan *out = *outSpans;
3938
3939     const QSpan *clipSpans = clip->m_spans + *currentClip;
3940     const QSpan *clipEnd = clip->m_spans + clip->count;
3941
3942     while (available && spans < end ) {
3943         if (clipSpans >= clipEnd) {
3944             spans = end;
3945             break;
3946         }
3947         if (clipSpans->y > spans->y) {
3948             ++spans;
3949             continue;
3950         }
3951         if (spans->y != clipSpans->y) {
3952             if (spans->y < clip->count && clip->m_clipLines[spans->y].spans)
3953                 clipSpans = clip->m_clipLines[spans->y].spans;
3954             else
3955                 ++clipSpans;
3956             continue;
3957         }
3958         Q_ASSERT(spans->y == clipSpans->y);
3959
3960         int sx1 = spans->x;
3961         int sx2 = sx1 + spans->len;
3962         int cx1 = clipSpans->x;
3963         int cx2 = cx1 + clipSpans->len;
3964
3965         if (cx1 < sx1 && cx2 < sx1) {
3966             ++clipSpans;
3967             continue;
3968         } else if (sx1 < cx1 && sx2 < cx1) {
3969             ++spans;
3970             continue;
3971         }
3972         int x = qMax(sx1, cx1);
3973         int len = qMin(sx2, cx2) - x;
3974         if (len) {
3975             out->x = qMax(sx1, cx1);
3976             out->len = qMin(sx2, cx2) - out->x;
3977             out->y = spans->y;
3978             out->coverage = qt_div_255(spans->coverage * clipSpans->coverage);
3979             ++out;
3980             --available;
3981         }
3982         if (sx2 < cx2) {
3983             ++spans;
3984         } else {
3985             ++clipSpans;
3986         }
3987     }
3988
3989     *outSpans = out;
3990     *currentClip = clipSpans - clip->m_spans;
3991     return spans;
3992 }
3993
3994 static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userData)
3995 {
3996 //     qDebug() << "qt_span_fill_clipped" << spanCount;
3997     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
3998
3999     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4000
4001     const int NSPANS = 256;
4002     QSpan cspans[NSPANS];
4003     int currentClip = 0;
4004     const QSpan *end = spans + spanCount;
4005     while (spans < end) {
4006         QSpan *clipped = cspans;
4007         spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
4008 //         qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
4009 //                  << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
4010
4011         if (clipped - cspans)
4012             fillData->unclipped_blend(clipped - cspans, cspans, fillData);
4013     }
4014 }
4015
4016 /*
4017     \internal
4018     Clip spans to \a{clip}-rectangle.
4019     Returns number of unclipped spans
4020 */
4021 static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4022                               const QRect &clip)
4023 {
4024     const short minx = clip.left();
4025     const short miny = clip.top();
4026     const short maxx = clip.right();
4027     const short maxy = clip.bottom();
4028
4029     int n = 0;
4030     for (int i = 0; i < numSpans; ++i) {
4031         if (spans[i].y > maxy)
4032             break;
4033         if (spans[i].y < miny
4034             || spans[i].x > maxx
4035             || spans[i].x + spans[i].len <= minx) {
4036             continue;
4037         }
4038         if (spans[i].x < minx) {
4039             spans[n].len = qMin(spans[i].len - (minx - spans[i].x), maxx - minx + 1);
4040             spans[n].x = minx;
4041         } else {
4042             spans[n].x = spans[i].x;
4043             spans[n].len = qMin(spans[i].len, ushort(maxx - spans[n].x + 1));
4044         }
4045         if (spans[n].len == 0)
4046             continue;
4047         spans[n].y = spans[i].y;
4048         spans[n].coverage = spans[i].coverage;
4049         ++n;
4050     }
4051     return n;
4052 }
4053
4054
4055 static void qt_span_fill_clipRect(int count, const QSpan *spans,
4056                                   void *userData)
4057 {
4058     QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4059     Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4060
4061     Q_ASSERT(fillData->clip);
4062     Q_ASSERT(!fillData->clip->clipRect.isEmpty());
4063
4064     // hw: check if this const_cast<> is safe!!!
4065     count = qt_intersect_spans(const_cast<QSpan*>(spans), count,
4066                                fillData->clip->clipRect);
4067     if (count > 0)
4068         fillData->unclipped_blend(count, spans, fillData);
4069 }
4070
4071 static void qt_span_clip(int count, const QSpan *spans, void *userData)
4072 {
4073     ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4074
4075 //     qDebug() << " qt_span_clip: " << count << clipData->operation;
4076 //     for (int i = 0; i < qMin(count, 10); ++i) {
4077 //         qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4078 //     }
4079
4080     switch (clipData->operation) {
4081
4082     case Qt::IntersectClip:
4083         {
4084             QClipData *newClip = clipData->newClip;
4085             newClip->initialize();
4086
4087             int currentClip = 0;
4088             const QSpan *end = spans + count;
4089             while (spans < end) {
4090                 QSpan *newspans = newClip->m_spans + newClip->count;
4091                 spans = qt_intersect_spans(clipData->oldClip, &currentClip, spans, end,
4092                                            &newspans, newClip->allocated - newClip->count);
4093                 newClip->count = newspans - newClip->m_spans;
4094                 if (spans < end) {
4095                     newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4096                     newClip->allocated *= 2;
4097                 }
4098             }
4099         }
4100         break;
4101
4102     case Qt::ReplaceClip:
4103         clipData->newClip->appendSpans(spans, count);
4104         break;
4105     case Qt::NoClip:
4106         break;
4107     }
4108 }
4109
4110 #ifndef QT_NO_DEBUG
4111 QImage QRasterBuffer::bufferImage() const
4112 {
4113     QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
4114
4115     for (int y = 0; y < m_height; ++y) {
4116         uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4117
4118         for (int x=0; x<m_width; ++x) {
4119             uint argb = span[x];
4120             image.setPixel(x, y, argb);
4121         }
4122     }
4123     return image;
4124 }
4125 #endif
4126
4127
4128 void QRasterBuffer::flushToARGBImage(QImage *target) const
4129 {
4130     int w = qMin(m_width, target->width());
4131     int h = qMin(m_height, target->height());
4132
4133     for (int y=0; y<h; ++y) {
4134         uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
4135         QRgb *dest = (QRgb *) target->scanLine(y);
4136         for (int x=0; x<w; ++x) {
4137             QRgb pixel = sourceLine[x];
4138             int alpha = qAlpha(pixel);
4139             if (!alpha) {
4140                 dest[x] = 0;
4141             } else {
4142                 dest[x] = (alpha << 24)
4143                         | ((255*qRed(pixel)/alpha) << 16)
4144                         | ((255*qGreen(pixel)/alpha) << 8)
4145                         | ((255*qBlue(pixel)/alpha) << 0);
4146             }
4147         }
4148     }
4149 }
4150
4151
4152 class QGradientCache
4153 {
4154     struct CacheInfo
4155     {
4156         inline CacheInfo(QGradientStops s, int op, QGradient::InterpolationMode mode) :
4157             stops(s), opacity(op), interpolationMode(mode) {}
4158         uint buffer[GRADIENT_STOPTABLE_SIZE];
4159         QGradientStops stops;
4160         int opacity;
4161         QGradient::InterpolationMode interpolationMode;
4162     };
4163
4164     typedef QMultiHash<quint64, CacheInfo> QGradientColorTableHash;
4165
4166 public:
4167     inline const uint *getBuffer(const QGradient &gradient, int opacity) {
4168         quint64 hash_val = 0;
4169
4170         QGradientStops stops = gradient.stops();
4171         for (int i = 0; i < stops.size() && i <= 2; i++)
4172             hash_val += stops[i].second.rgba();
4173
4174         QMutexLocker lock(&mutex);
4175         QGradientColorTableHash::const_iterator it = cache.constFind(hash_val);
4176
4177         if (it == cache.constEnd())
4178             return addCacheElement(hash_val, gradient, opacity);
4179         else {
4180             do {
4181                 const CacheInfo &cache_info = it.value();
4182                 if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode())
4183                     return cache_info.buffer;
4184                 ++it;
4185             } while (it != cache.constEnd() && it.key() == hash_val);
4186             // an exact match for these stops and opacity was not found, create new cache
4187             return addCacheElement(hash_val, gradient, opacity);
4188         }
4189     }
4190
4191     inline int paletteSize() const { return GRADIENT_STOPTABLE_SIZE; }
4192 protected:
4193     inline int maxCacheSize() const { return 60; }
4194     inline void generateGradientColorTable(const QGradient& g,
4195                                            uint *colorTable,
4196                                            int size, int opacity) const;
4197     uint *addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
4198         if (cache.size() == maxCacheSize()) {
4199             // may remove more than 1, but OK
4200             cache.erase(cache.begin() + (qrand() % maxCacheSize()));
4201         }
4202         CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode());
4203         generateGradientColorTable(gradient, cache_entry.buffer, paletteSize(), opacity);
4204         return cache.insert(hash_val, cache_entry).value().buffer;
4205     }
4206
4207     QGradientColorTableHash cache;
4208     QMutex mutex;
4209 };
4210
4211 void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, int opacity) const
4212 {
4213     QGradientStops stops = gradient.stops();
4214     int stopCount = stops.count();
4215     Q_ASSERT(stopCount > 0);
4216
4217     bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
4218
4219     if (stopCount == 2) {
4220         uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4221         uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
4222
4223         qreal first_stop = stops[0].first;
4224         qreal second_stop = stops[1].first;
4225
4226         if (second_stop < first_stop) {
4227             qSwap(first_color, second_color);
4228             qSwap(first_stop, second_stop);
4229         }
4230
4231         if (colorInterpolation) {
4232             first_color = PREMUL(first_color);
4233             second_color = PREMUL(second_color);
4234         }
4235
4236         int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
4237         int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
4238
4239         uint red_first = qRed(first_color) << 16;
4240         uint green_first = qGreen(first_color) << 16;
4241         uint blue_first = qBlue(first_color) << 16;
4242         uint alpha_first = qAlpha(first_color) << 16;
4243
4244         uint red_second = qRed(second_color) << 16;
4245         uint green_second = qGreen(second_color) << 16;
4246         uint blue_second = qBlue(second_color) << 16;
4247         uint alpha_second = qAlpha(second_color) << 16;
4248
4249         int i = 0;
4250         for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
4251             if (colorInterpolation)
4252                 colorTable[i] = first_color;
4253             else
4254                 colorTable[i] = PREMUL(first_color);
4255         }
4256
4257         if (i < second_index) {
4258             qreal reciprocal = qreal(1) / (second_index - first_index);
4259
4260             int red_delta = qRound(int(red_second - red_first) * reciprocal);
4261             int green_delta = qRound(int(green_second - green_first) * reciprocal);
4262             int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
4263             int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
4264
4265             // rounding
4266             red_first += 1 << 15;
4267             green_first += 1 << 15;
4268             blue_first += 1 << 15;
4269             alpha_first += 1 << 15;
4270
4271             for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
4272                 red_first += red_delta;
4273                 green_first += green_delta;
4274                 blue_first += blue_delta;
4275                 alpha_first += alpha_delta;
4276
4277                 const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
4278                                  | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
4279
4280                 if (colorInterpolation)
4281                     colorTable[i] = color;
4282                 else
4283                     colorTable[i] = PREMUL(color);
4284             }
4285         }
4286
4287         for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
4288             if (colorInterpolation)
4289                 colorTable[i] = second_color;
4290             else
4291                 colorTable[i] = PREMUL(second_color);
4292         }
4293
4294         return;
4295     }
4296
4297     uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
4298     if (stopCount == 1) {
4299         current_color = PREMUL(current_color);
4300         for (int i = 0; i < size; ++i)
4301             colorTable[i] = current_color;
4302         return;
4303     }
4304
4305     // The position where the gradient begins and ends
4306     qreal begin_pos = stops[0].first;
4307     qreal end_pos = stops[stopCount-1].first;
4308
4309     int pos = 0; // The position in the color table.
4310     uint next_color;
4311
4312     qreal incr = 1 / qreal(size); // the double increment.
4313     qreal dpos = 1.5 * incr; // current position in gradient stop list (0 to 1)
4314
4315      // Up to first point
4316     colorTable[pos++] = PREMUL(current_color);
4317     while (dpos <= begin_pos) {
4318         colorTable[pos] = colorTable[pos - 1];
4319         ++pos;
4320         dpos += incr;
4321     }
4322
4323     int current_stop = 0; // We always interpolate between current and current + 1.
4324
4325     qreal t; // position between current left and right stops
4326     qreal t_delta; // the t increment per entry in the color table
4327
4328     if (dpos < end_pos) {
4329         // Gradient area
4330         while (dpos > stops[current_stop+1].first)
4331             ++current_stop;
4332
4333         if (current_stop != 0)
4334             current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4335         next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4336
4337         if (colorInterpolation) {
4338             current_color = PREMUL(current_color);
4339             next_color = PREMUL(next_color);
4340         }
4341
4342         qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4343         qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4344         t = (dpos - stops[current_stop].first) * c;
4345         t_delta = incr * c;
4346
4347         while (true) {
4348             Q_ASSERT(current_stop < stopCount);
4349
4350             int dist = qRound(t);
4351             int idist = 256 - dist;
4352
4353             if (colorInterpolation)
4354                 colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
4355             else
4356                 colorTable[pos] = PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
4357
4358             ++pos;
4359             dpos += incr;
4360
4361             if (dpos >= end_pos)
4362                 break;
4363
4364             t += t_delta;
4365
4366             int skip = 0;
4367             while (dpos > stops[current_stop+skip+1].first)
4368                 ++skip;
4369
4370             if (skip != 0) {
4371                 current_stop += skip;
4372                 if (skip == 1)
4373                     current_color = next_color;
4374                 else
4375                     current_color = ARGB_COMBINE_ALPHA(stops[current_stop].second.rgba(), opacity);
4376                 next_color = ARGB_COMBINE_ALPHA(stops[current_stop+1].second.rgba(), opacity);
4377
4378                 if (colorInterpolation) {
4379                     if (skip != 1)
4380                         current_color = PREMUL(current_color);
4381                     next_color = PREMUL(next_color);
4382                 }
4383
4384                 qreal diff = stops[current_stop+1].first - stops[current_stop].first;
4385                 qreal c = (diff == 0) ? qreal(0) : 256 / diff;
4386                 t = (dpos - stops[current_stop].first) * c;
4387                 t_delta = incr * c;
4388             }
4389         }
4390     }
4391
4392     // After last point
4393     current_color = PREMUL(ARGB_COMBINE_ALPHA(stops[stopCount - 1].second.rgba(), opacity));
4394     while (pos < size - 1) {
4395         colorTable[pos] = current_color;
4396         ++pos;
4397     }
4398
4399     // Make sure the last color stop is represented at the end of the table
4400     colorTable[size - 1] = current_color;
4401 }
4402
4403 Q_GLOBAL_STATIC(QGradientCache, qt_gradient_cache)
4404
4405
4406 void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
4407 {
4408     rasterBuffer = rb;
4409     type = None;
4410     txop = 0;
4411     bilinear = false;
4412     m11 = m22 = m33 = 1.;
4413     m12 = m13 = m21 = m23 = dx = dy = 0.0;
4414     clip = pe ? pe->d_func()->clip() : 0;
4415 }
4416
4417 Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
4418
4419 void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
4420 {
4421     Qt::BrushStyle brushStyle = qbrush_style(brush);
4422     switch (brushStyle) {
4423     case Qt::SolidPattern: {
4424         type = Solid;
4425         QColor c = qbrush_color(brush);
4426         QRgb rgba = c.rgba();
4427         solid.color = PREMUL(ARGB_COMBINE_ALPHA(rgba, alpha));
4428         if ((solid.color & 0xff000000) == 0
4429             && compositionMode == QPainter::CompositionMode_SourceOver) {
4430             type = None;
4431         }
4432         break;
4433     }
4434
4435     case Qt::LinearGradientPattern:
4436         {
4437             type = LinearGradient;
4438             const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient());
4439             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4440             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4441             gradient.spread = g->spread();
4442
4443             QLinearGradientData &linearData = gradient.linear;
4444
4445             linearData.origin.x = g->start().x();
4446             linearData.origin.y = g->start().y();
4447             linearData.end.x = g->finalStop().x();
4448             linearData.end.y = g->finalStop().y();
4449             break;
4450         }
4451
4452     case Qt::RadialGradientPattern:
4453         {
4454             type = RadialGradient;
4455             const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient());
4456             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4457             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4458             gradient.spread = g->spread();
4459
4460             QRadialGradientData &radialData = gradient.radial;
4461
4462             QPointF center = g->center();
4463             radialData.center.x = center.x();
4464             radialData.center.y = center.y();
4465             radialData.center.radius = g->centerRadius();
4466             QPointF focal = g->focalPoint();
4467             radialData.focal.x = focal.x();
4468             radialData.focal.y = focal.y();
4469             radialData.focal.radius = g->focalRadius();
4470         }
4471         break;
4472
4473     case Qt::ConicalGradientPattern:
4474         {
4475             type = ConicalGradient;
4476             const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient());
4477             gradient.alphaColor = !brush.isOpaque() || alpha != 256;
4478             gradient.colorTable = const_cast<uint*>(qt_gradient_cache()->getBuffer(*g, alpha));
4479             gradient.spread = QGradient::RepeatSpread;
4480
4481             QConicalGradientData &conicalData = gradient.conical;
4482
4483             QPointF center = g->center();
4484             conicalData.center.x = center.x();
4485             conicalData.center.y = center.y();
4486             conicalData.angle = g->angle() * 2 * Q_PI / 360.0;
4487         }
4488         break;
4489
4490     case Qt::Dense1Pattern:
4491     case Qt::Dense2Pattern:
4492     case Qt::Dense3Pattern:
4493     case Qt::Dense4Pattern:
4494     case Qt::Dense5Pattern:
4495     case Qt::Dense6Pattern:
4496     case Qt::Dense7Pattern:
4497     case Qt::HorPattern:
4498     case Qt::VerPattern:
4499     case Qt::CrossPattern:
4500     case Qt::BDiagPattern:
4501     case Qt::FDiagPattern:
4502     case Qt::DiagCrossPattern:
4503         type = Texture;
4504         if (!tempImage)
4505             tempImage = new QImage();
4506         *tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
4507         initTexture(tempImage, alpha, QTextureData::Tiled);
4508         break;
4509     case Qt::TexturePattern:
4510         type = Texture;
4511         if (!tempImage)
4512             tempImage = new QImage();
4513
4514         if (qHasPixmapTexture(brush) && brush.texture().isQBitmap())
4515             *tempImage = rasterBuffer->colorizeBitmap(brush.textureImage(), brush.color());
4516         else
4517             *tempImage = brush.textureImage();
4518         initTexture(tempImage, alpha, QTextureData::Tiled, tempImage->rect());
4519         break;
4520
4521     case Qt::NoBrush:
4522     default:
4523         type = None;
4524         break;
4525     }
4526     adjustSpanMethods();
4527 }
4528
4529 void QSpanData::adjustSpanMethods()
4530 {
4531     bitmapBlit = 0;
4532     alphamapBlit = 0;
4533     alphaRGBBlit = 0;
4534
4535     fillRect = 0;
4536
4537     switch(type) {
4538     case None:
4539         unclipped_blend = 0;
4540         break;
4541     case Solid:
4542         unclipped_blend = rasterBuffer->drawHelper->blendColor;
4543         bitmapBlit = rasterBuffer->drawHelper->bitmapBlit;
4544         alphamapBlit = rasterBuffer->drawHelper->alphamapBlit;
4545         alphaRGBBlit = rasterBuffer->drawHelper->alphaRGBBlit;
4546         fillRect = rasterBuffer->drawHelper->fillRect;
4547         break;
4548     case LinearGradient:
4549     case RadialGradient:
4550     case ConicalGradient:
4551         unclipped_blend = rasterBuffer->drawHelper->blendGradient;
4552         break;
4553     case Texture:
4554         unclipped_blend = qBlendTexture;
4555         if (!texture.imageData)
4556             unclipped_blend = 0;
4557
4558         break;
4559     }
4560     // setup clipping
4561     if (!unclipped_blend) {
4562         blend = 0;
4563     } else if (!clip) {
4564         blend = unclipped_blend;
4565     } else if (clip->hasRectClip) {
4566         blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
4567     } else {
4568         blend = qt_span_fill_clipped;
4569     }
4570 }
4571
4572 void QSpanData::setupMatrix(const QTransform &matrix, int bilin)
4573 {
4574     QTransform delta;
4575     // make sure we round off correctly in qdrawhelper.cpp
4576     delta.translate(1.0 / 65536, 1.0 / 65536);
4577
4578     QTransform inv = (delta * matrix).inverted();
4579     m11 = inv.m11();
4580     m12 = inv.m12();
4581     m13 = inv.m13();
4582     m21 = inv.m21();
4583     m22 = inv.m22();
4584     m23 = inv.m23();
4585     m33 = inv.m33();
4586     dx = inv.dx();
4587     dy = inv.dy();
4588     txop = inv.type();
4589     bilinear = bilin;
4590
4591     const bool affine = !m13 && !m23;
4592     fast_matrix = affine
4593         && m11 * m11 + m21 * m21 < 1e4
4594         && m12 * m12 + m22 * m22 < 1e4
4595         && qAbs(dx) < 1e4
4596         && qAbs(dy) < 1e4;
4597
4598     adjustSpanMethods();
4599 }
4600
4601 void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _type, const QRect &sourceRect)
4602 {
4603     const QImageData *d = const_cast<QImage *>(image)->data_ptr();
4604     if (!d || d->height == 0) {
4605         texture.imageData = 0;
4606         texture.width = 0;
4607         texture.height = 0;
4608         texture.x1 = 0;
4609         texture.y1 = 0;
4610         texture.x2 = 0;
4611         texture.y2 = 0;
4612         texture.bytesPerLine = 0;
4613         texture.format = QImage::Format_Invalid;
4614         texture.colorTable = 0;
4615         texture.hasAlpha = alpha != 256;
4616     } else {
4617         texture.imageData = d->data;
4618         texture.width = d->width;
4619         texture.height = d->height;
4620
4621         if (sourceRect.isNull()) {
4622             texture.x1 = 0;
4623             texture.y1 = 0;
4624             texture.x2 = texture.width;
4625             texture.y2 = texture.height;
4626         } else {
4627             texture.x1 = sourceRect.x();
4628             texture.y1 = sourceRect.y();
4629             texture.x2 = qMin(texture.x1 + sourceRect.width(), d->width);
4630             texture.y2 = qMin(texture.y1 + sourceRect.height(), d->height);
4631         }
4632
4633         texture.bytesPerLine = d->bytes_per_line;
4634
4635         texture.format = d->format;
4636         texture.colorTable = (d->format <= QImage::Format_Indexed8 && !d->colortable.isEmpty()) ? &d->colortable : 0;
4637         texture.hasAlpha = image->hasAlphaChannel() || alpha != 256;
4638     }
4639     texture.const_alpha = alpha;
4640     texture.type = _type;
4641
4642     adjustSpanMethods();
4643 }
4644
4645 /*!
4646     \internal
4647     \a x and \a y is relative to the midpoint of \a rect.
4648 */
4649 static inline void drawEllipsePoints(int x, int y, int length,
4650                                      const QRect &rect,
4651                                      const QRect &clip,
4652                                      ProcessSpans pen_func, ProcessSpans brush_func,
4653                                      QSpanData *pen_data, QSpanData *brush_data)
4654 {
4655     if (length == 0)
4656         return;
4657
4658     QT_FT_Span outline[4];
4659     const int midx = rect.x() + (rect.width() + 1) / 2;
4660     const int midy = rect.y() + (rect.height() + 1) / 2;
4661
4662     x = x + midx;
4663     y = midy - y;
4664
4665     // topleft
4666     outline[0].x = midx + (midx - x) - (length - 1) - (rect.width() & 0x1);
4667     outline[0].len = qMin(length, x - outline[0].x);
4668     outline[0].y = y;
4669     outline[0].coverage = 255;
4670
4671     // topright
4672     outline[1].x = x;
4673     outline[1].len = length;
4674     outline[1].y = y;
4675     outline[1].coverage = 255;
4676
4677     // bottomleft
4678     outline[2].x = outline[0].x;
4679     outline[2].len = outline[0].len;
4680     outline[2].y = midy + (midy - y) - (rect.height() & 0x1);
4681     outline[2].coverage = 255;
4682
4683     // bottomright
4684     outline[3].x = x;
4685     outline[3].len = length;
4686     outline[3].y = outline[2].y;
4687     outline[3].coverage = 255;
4688
4689     if (brush_func && outline[0].x + outline[0].len < outline[1].x) {
4690         QT_FT_Span fill[2];
4691
4692         // top fill
4693         fill[0].x = outline[0].x + outline[0].len - 1;
4694         fill[0].len = qMax(0, outline[1].x - fill[0].x);
4695         fill[0].y = outline[1].y;
4696         fill[0].coverage = 255;
4697
4698         // bottom fill
4699         fill[1].x = outline[2].x + outline[2].len - 1;
4700         fill[1].len = qMax(0, outline[3].x - fill[1].x);
4701         fill[1].y = outline[3].y;
4702         fill[1].coverage = 255;
4703
4704         int n = (fill[0].y >= fill[1].y ? 1 : 2);
4705         n = qt_intersect_spans(fill, n, clip);
4706         if (n > 0)
4707             brush_func(n, fill, brush_data);
4708     }
4709     if (pen_func) {
4710         int n = (outline[1].y >= outline[2].y ? 2 : 4);
4711         n = qt_intersect_spans(outline, n, clip);
4712         if (n > 0)
4713             pen_func(n, outline, pen_data);
4714     }
4715 }
4716
4717 /*!
4718     \internal
4719     Draws an ellipse using the integer point midpoint algorithm.
4720 */
4721 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
4722                                    ProcessSpans pen_func, ProcessSpans brush_func,
4723                                    QSpanData *pen_data, QSpanData *brush_data)
4724 {
4725     const qreal a = qreal(rect.width()) / 2;
4726     const qreal b = qreal(rect.height()) / 2;
4727     qreal d = b*b - (a*a*b) + 0.25*a*a;
4728
4729     int x = 0;
4730     int y = (rect.height() + 1) / 2;
4731     int startx = x;
4732
4733     // region 1
4734     while (a*a*(2*y - 1) > 2*b*b*(x + 1)) {
4735         if (d < 0) { // select E
4736             d += b*b*(2*x + 3);
4737             ++x;
4738         } else {     // select SE
4739             d += b*b*(2*x + 3) + a*a*(-2*y + 2);
4740             drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4741                               pen_func, brush_func, pen_data, brush_data);
4742             startx = ++x;
4743             --y;
4744         }
4745     }
4746     drawEllipsePoints(startx, y, x - startx + 1, rect, clip,
4747                       pen_func, brush_func, pen_data, brush_data);
4748
4749     // region 2
4750     d = b*b*(x + 0.5)*(x + 0.5) + a*a*((y - 1)*(y - 1) - b*b);
4751     const int miny = rect.height() & 0x1;
4752     while (y > miny) {
4753         if (d < 0) { // select SE
4754             d += b*b*(2*x + 2) + a*a*(-2*y + 3);
4755             ++x;
4756         } else {     // select S
4757             d += a*a*(-2*y + 3);
4758         }
4759         --y;
4760         drawEllipsePoints(x, y, 1, rect, clip,
4761                           pen_func, brush_func, pen_data, brush_data);
4762     }
4763 }
4764
4765 /*!
4766     \fn void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
4767     \overload
4768     \reimp
4769 */
4770
4771
4772 #ifdef QT_DEBUG_DRAW
4773 void dumpClip(int width, int height, const QClipData *clip)
4774 {
4775     QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
4776     clipImg.fill(0xffff0000);
4777
4778     int x0 = width;
4779     int x1 = 0;
4780     int y0 = height;
4781     int y1 = 0;
4782
4783     ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
4784
4785     for (int i = 0; i < clip->count; ++i) {
4786         const QSpan *span = ((QClipData *) clip)->spans() + i;
4787         for (int j = 0; j < span->len; ++j)
4788             clipImg.setPixel(span->x + j, span->y, 0xffffff00);
4789         x0 = qMin(x0, int(span->x));
4790         x1 = qMax(x1, int(span->x + span->len - 1));
4791
4792         y0 = qMin(y0, int(span->y));
4793         y1 = qMax(y1, int(span->y));
4794     }
4795
4796     static int counter = 0;
4797
4798     Q_ASSERT(y0 >= 0);
4799     Q_ASSERT(x0 >= 0);
4800     Q_ASSERT(y1 >= 0);
4801     Q_ASSERT(x1 >= 0);
4802
4803     fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
4804     clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
4805 }
4806 #endif
4807
4808
4809 QT_END_NAMESPACE