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