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