Merge remote branch 'origin/4.6' into qt-4.7-from-4.6
[qt:qt-ios-plaszma.git] / src / gui / painting / qpaintengine_raster.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtCore/qglobal.h>
43 #include <QtCore/qmutex.h>
44
45 #define QT_FT_BEGIN_HEADER
46 #define QT_FT_END_HEADER
47
48 #include <private/qrasterdefs_p.h>
49 #include <private/qgrayraster_p.h>
50
51 #include <qpainterpath.h>
52 #include <qdebug.h>
53 #include <qhash.h>
54 #include <qlabel.h>
55 #include <qbitmap.h>
56 #include <qmath.h>
57
58 #if defined (Q_WS_X11)
59 #  include <private/qfontengine_ft_p.h>
60 #endif
61
62 //   #include <private/qdatabuffer_p.h>
63 //   #include <private/qpainter_p.h>
64 #include <private/qmath_p.h>
65 #include <private/qtextengine_p.h>
66 #include <private/qfontengine_p.h>
67 #include <private/qpixmap_raster_p.h>
68 //   #include <private/qpolygonclipper_p.h>
69 //   #include <private/qrasterizer_p.h>
70 #include <private/qimage_p.h>
71 #include <private/qstatictext_p.h>
72 #include "qmemrotate_p.h"
73
74 #include "qpaintengine_raster_p.h"
75 //   #include "qbezier_p.h"
76 #include "qoutlinemapper_p.h"
77
78 #if defined(Q_WS_WIN)
79 #  include <qt_windows.h>
80 #  include <qvarlengtharray.h>
81 #  include <private/qfontengine_p.h>
82 #  if defined(Q_OS_WINCE)
83 #    include "qguifunctions_wince.h"
84 #  endif
85 #elif defined(Q_WS_MAC)
86 #  include <private/qt_mac_p.h>
87 #  include <private/qpixmap_mac_p.h>
88 #  include <private/qpaintengine_mac_p.h>
89 #elif defined(Q_WS_QWS)
90 #  if !defined(QT_NO_FREETYPE)
91 #    include <private/qfontengine_ft_p.h>
92 #  endif
93 #  if !defined(QT_NO_QWS_QPF2)
94 #    include <private/qfontengine_qpf_p.h>
95 #  endif
96 #  include <private/qabstractfontengine_p.h>
97 #elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
98 #  include <private/qfontengine_s60_p.h>
99 #endif
100
101 #if defined(Q_WS_WIN64)
102 #  include <malloc.h>
103 #endif
104 #include <limits.h>
105
106 QT_BEGIN_NAMESPACE
107
108 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
109
110 #define qreal_to_fixed_26_6(f) (int(f * 64))
111 #define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
112 #define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
113
114 // #define QT_DEBUG_DRAW
115 #ifdef QT_DEBUG_DRAW
116 void dumpClip(int width, int height, const QClipData *clip);
117 #endif
118
119 #define QT_FAST_SPANS
120
121
122 // A little helper macro to get a better approximation of dimensions.
123 // If we have a rect that starting at 0.5 of width 3.5 it should span
124 // 4 pixels.
125 #define int_dim(pos, dim) (int(pos+dim) - int(pos))
126
127 // use the same rounding as in qrasterizer.cpp (6 bit fixed point)
128 static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
129
130 #ifdef Q_WS_WIN
131 extern bool qt_cleartype_enabled;
132 #endif
133
134 #ifdef Q_WS_MAC
135 extern bool qt_applefontsmoothing_enabled;
136 #endif
137
138
139 /********************************************************************************
140  * Span functions
141  */
142 static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
143 static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
144 static void qt_span_clip(int count, const QSpan *spans, void *userData);
145 static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
146
147 struct ClipData
148 {
149     QClipData *oldClip;
150     QClipData *newClip;
151     Qt::ClipOperation operation;
152 };
153
154 enum LineDrawMode {
155     LineDrawClipped,
156     LineDrawNormal,
157     LineDrawIncludeLastPixel
158 };
159
160 static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data,
161                                 LineDrawMode style, const QIntRect &rect);
162 static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2,
163                                        QPen *pen, ProcessSpans span_func, QSpanData *data,
164                                        LineDrawMode style, const QIntRect &devRect,
165                                        int *patternOffset);
166 // static void drawLine_midpoint_f(qreal x1, qreal y1, qreal x2, qreal y2,
167 //                                 ProcessSpans span_func, QSpanData *data,
168 //                                 LineDrawMode style, const QRect &devRect);
169
170 static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
171                                    ProcessSpans pen_func, ProcessSpans brush_func,
172                                    QSpanData *pen_data, QSpanData *brush_data);
173
174 struct QRasterFloatPoint {
175     qreal x;
176     qreal y;
177 };
178
179 #ifdef QT_DEBUG_DRAW
180 static const QRectF boundingRect(const QPointF *points, int pointCount)
181 {
182     const QPointF *e = points;
183     const QPointF *last = points + pointCount;
184     qreal minx, maxx, miny, maxy;
185     minx = maxx = e->x();
186     miny = maxy = e->y();
187     while (++e < last) {
188         if (e->x() < minx)
189             minx = e->x();
190         else if (e->x() > maxx)
191             maxx = e->x();
192         if (e->y() < miny)
193             miny = e->y();
194         else if (e->y() > maxy)
195             maxy = e->y();
196     }
197     return QRectF(QPointF(minx, miny), QPointF(maxx, maxy));
198 }
199 #endif
200
201 template <typename T> static inline bool isRect(const T *pts, int elementCount) {
202     return (elementCount == 5 // 5-point polygon, check for closed rect
203             && pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
204             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
205             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
206             && pts[0] < pts[4] && pts[1] < pts[5]
207             ) ||
208            (elementCount == 4 // 4-point polygon, check for unclosed rect
209             && pts[0] == pts[6] && pts[2] == pts[4] // x values equal
210             && pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
211             && pts[0] < pts[4] && pts[1] < pts[5]
212             );
213 }
214
215
216 static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
217 {
218     ((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
219 }
220
221 static void qt_ft_outline_line_to(qfixed x, qfixed y, void *data)
222 {
223     ((QOutlineMapper *) data)->lineTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
224 }
225
226 static void qt_ft_outline_cubic_to(qfixed c1x, qfixed c1y,
227                              qfixed c2x, qfixed c2y,
228                              qfixed ex, qfixed ey,
229                              void *data)
230 {
231     ((QOutlineMapper *) data)->curveTo(QPointF(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y)),
232                                        QPointF(qt_fixed_to_real(c2x), qt_fixed_to_real(c2y)),
233                                        QPointF(qt_fixed_to_real(ex), qt_fixed_to_real(ey)));
234 }
235
236
237 #if !defined(QT_NO_DEBUG) && 0
238 static void qt_debug_path(const QPainterPath &path)
239 {
240     const char *names[] = {
241         "MoveTo     ",
242         "LineTo     ",
243         "CurveTo    ",
244         "CurveToData"
245     };
246
247     fprintf(stderr,"\nQPainterPath: elementCount=%d\n", path.elementCount());
248     for (int i=0; i<path.elementCount(); ++i) {
249         const QPainterPath::Element &e = path.elementAt(i);
250         Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
251         fprintf(stderr," - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
252     }
253 }
254 #endif
255
256 QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
257     QPaintEngineExPrivate(),
258     cachedLines(0)
259 {
260 }
261
262
263 /*!
264     \class QRasterPaintEngine
265     \preliminary
266     \ingroup qws
267     \since 4.2
268
269     \brief The QRasterPaintEngine class enables hardware acceleration
270     of painting operations in Qt for Embedded Linux.
271
272     Note that this functionality is only available in
273     \l{Qt for Embedded Linux}.
274
275     In \l{Qt for Embedded Linux}, painting is a pure software
276     implementation. But starting with Qt 4.2, it is
277     possible to add an accelerated graphics driver to take advantage
278     of available hardware resources.
279
280     Hardware acceleration is accomplished by creating a custom screen
281     driver, accelerating the copying from memory to the screen, and
282     implementing a custom paint engine accelerating the various
283     painting operations. Then a custom paint device (derived from the
284     QCustomRasterPaintDevice class) and a custom window surface
285     (derived from QWSWindowSurface) must be implemented to make
286     \l{Qt for Embedded Linux} aware of the accelerated driver.
287
288     \note The QRasterPaintEngine class does not support 8-bit images.
289     Instead, they need to be converted to a supported format, such as
290     QImage::Format_ARGB32_Premultiplied.
291
292     See the \l {Adding an Accelerated Graphics Driver to Qt for Embedded Linux}
293     documentation for details.
294
295     \sa QCustomRasterPaintDevice, QPaintEngine
296 */
297
298 /*!
299     \fn Type QRasterPaintEngine::type() const
300     \reimp
301 */
302
303 /*!
304     \typedef QSpan
305     \relates QRasterPaintEngine
306
307     A struct equivalent to QT_FT_Span, containing a position (x,
308     y), the span's length in pixels and its color/coverage (a value
309     ranging from 0 to 255).
310 */
311
312 /*!
313     \since 4.5
314
315     Creates a raster based paint engine for operating on the given
316     \a device, with the complete set of \l
317     {QPaintEngine::PaintEngineFeature}{paint engine features and
318     capabilities}.
319 */
320 QRasterPaintEngine::QRasterPaintEngine(QPaintDevice *device)
321     : QPaintEngineEx(*(new QRasterPaintEnginePrivate))
322 {
323     d_func()->device = device;
324     init();
325 }
326
327 /*!
328     \internal
329 */
330 QRasterPaintEngine::QRasterPaintEngine(QRasterPaintEnginePrivate &dd, QPaintDevice *device)
331     : QPaintEngineEx(dd)
332 {
333     d_func()->device = device;
334     init();
335 }
336
337 void QRasterPaintEngine::init()
338 {
339     Q_D(QRasterPaintEngine);
340
341
342 #ifdef Q_WS_WIN
343     d->hdc = 0;
344 #endif
345
346     // The antialiasing raster.
347     d->grayRaster.reset(new QT_FT_Raster);
348     Q_CHECK_PTR(d->grayRaster.data());
349     if (qt_ft_grays_raster.raster_new(d->grayRaster.data()))
350         QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
351
352
353     d->rasterizer.reset(new QRasterizer);
354     d->rasterBuffer.reset(new QRasterBuffer());
355     d->outlineMapper.reset(new QOutlineMapper);
356     d->outlinemapper_xform_dirty = true;
357
358     d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
359     d->basicStroker.setLineToHook(qt_ft_outline_line_to);
360     d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
361
362     d->baseClip.reset(new QClipData(d->device->height()));
363     d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
364
365     d->image_filler.init(d->rasterBuffer.data(), this);
366     d->image_filler.type = QSpanData::Texture;
367
368     d->image_filler_xform.init(d->rasterBuffer.data(), this);
369     d->image_filler_xform.type = QSpanData::Texture;
370
371     d->solid_color_filler.init(d->rasterBuffer.data(), this);
372     d->solid_color_filler.type = QSpanData::Solid;
373
374     d->deviceDepth = d->device->depth();
375
376     d->mono_surface = false;
377     gccaps &= ~PorterDuff;
378
379     QImage::Format format = QImage::Format_Invalid;
380
381     switch (d->device->devType()) {
382     case QInternal::Pixmap:
383         qWarning("QRasterPaintEngine: unsupported for pixmaps...");
384         break;
385     case QInternal::Image:
386         format = d->rasterBuffer->prepare(static_cast<QImage *>(d->device));
387         break;
388 #ifdef Q_WS_QWS
389     case QInternal::CustomRaster:
390         d->rasterBuffer->prepare(static_cast<QCustomRasterPaintDevice*>(d->device));
391         break;
392 #endif
393     default:
394         qWarning("QRasterPaintEngine: unsupported target device %d\n", d->device->devType());
395         d->device = 0;
396         return;
397     }
398
399     switch (format) {
400     case QImage::Format_MonoLSB:
401     case QImage::Format_Mono:
402         d->mono_surface = true;
403         break;
404     case QImage::Format_ARGB8565_Premultiplied:
405     case QImage::Format_ARGB8555_Premultiplied:
406     case QImage::Format_ARGB6666_Premultiplied:
407     case QImage::Format_ARGB4444_Premultiplied:
408     case QImage::Format_ARGB32_Premultiplied:
409     case QImage::Format_ARGB32:
410         gccaps |= PorterDuff;
411         break;
412     case QImage::Format_RGB32:
413     case QImage::Format_RGB444:
414     case QImage::Format_RGB555:
415     case QImage::Format_RGB666:
416     case QImage::Format_RGB888:
417     case QImage::Format_RGB16:
418         break;
419     default:
420         break;
421     }
422 }
423
424
425
426
427 /*!
428     Destroys this paint engine.
429 */
430 QRasterPaintEngine::~QRasterPaintEngine()
431 {
432     Q_D(QRasterPaintEngine);
433
434     qt_ft_grays_raster.raster_done(*d->grayRaster.data());
435 }
436
437 /*!
438     \reimp
439 */
440 bool QRasterPaintEngine::begin(QPaintDevice *device)
441 {
442     Q_D(QRasterPaintEngine);
443
444     if (device->devType() == QInternal::Pixmap) {
445         QPixmap *pixmap = static_cast<QPixmap *>(device);
446         QPixmapData *pd = pixmap->pixmapData();
447         if (pd->classId() == QPixmapData::RasterClass)
448             d->device = pd->buffer();
449     } else {
450         d->device = device;
451     }
452
453     // Make sure QPaintEngine::paintDevice() returns the proper device.
454     d->pdev = d->device;
455
456     Q_ASSERT(d->device->devType() == QInternal::Image
457              || d->device->devType() == QInternal::CustomRaster);
458
459     d->systemStateChanged();
460
461     QRasterPaintEngineState *s = state();
462     ensureOutlineMapper();
463     d->outlineMapper->m_clip_rect = d->deviceRect;
464
465     if (d->outlineMapper->m_clip_rect.width() > QT_RASTER_COORD_LIMIT)
466         d->outlineMapper->m_clip_rect.setWidth(QT_RASTER_COORD_LIMIT);
467     if (d->outlineMapper->m_clip_rect.height() > QT_RASTER_COORD_LIMIT)
468         d->outlineMapper->m_clip_rect.setHeight(QT_RASTER_COORD_LIMIT);
469
470     d->rasterizer->setClipRect(d->deviceRect);
471
472     s->penData.init(d->rasterBuffer.data(), this);
473     s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
474     s->stroker = &d->basicStroker;
475     d->basicStroker.setClipRect(d->deviceRect);
476
477     s->brushData.init(d->rasterBuffer.data(), this);
478     s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
479
480     d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
481
482     setDirty(DirtyBrushOrigin);
483
484 #ifdef QT_DEBUG_DRAW
485     qDebug() << "QRasterPaintEngine::begin(" << (void *) device
486              << ") devType:" << device->devType()
487              << "devRect:" << d->deviceRect;
488     if (d->baseClip) {
489         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
490     }
491 #endif
492
493 #if defined(Q_WS_WIN)
494     d->isPlain45DegreeRotation = true;
495 #endif
496
497     if (d->mono_surface)
498         d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
499 #if defined(Q_WS_WIN)
500     else if (qt_cleartype_enabled)
501 #elif defined (Q_WS_MAC)
502     else if (qt_applefontsmoothing_enabled)
503 #else
504     else if (false)
505 #endif
506     {
507         QImage::Format format = static_cast<QImage *>(d->device)->format();
508         if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
509             d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
510         else
511             d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
512     } else
513         d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
514
515     setActive(true);
516     return true;
517 }
518
519 /*!
520     \reimp
521 */
522 bool QRasterPaintEngine::end()
523 {
524 #ifdef QT_DEBUG_DRAW
525     Q_D(QRasterPaintEngine);
526     qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
527     if (d->baseClip) {
528         dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
529     }
530 #endif
531
532     return true;
533 }
534
535 /*!
536     \internal
537 */
538 void QRasterPaintEngine::releaseBuffer()
539 {
540     Q_D(QRasterPaintEngine);
541     d->rasterBuffer.reset(new QRasterBuffer);
542 }
543
544 /*!
545     \internal
546 */
547 QSize QRasterPaintEngine::size() const
548 {
549     Q_D(const QRasterPaintEngine);
550     return QSize(d->rasterBuffer->width(), d->rasterBuffer->height());
551 }
552
553 /*!
554     \internal
555 */
556 #ifndef QT_NO_DEBUG
557 void QRasterPaintEngine::saveBuffer(const QString &s) const
558 {
559     Q_D(const QRasterPaintEngine);
560     d->rasterBuffer->bufferImage().save(s, "PNG");
561 }
562 #endif
563
564 /*!
565     \internal
566 */
567 void QRasterPaintEngine::updateMatrix(const QTransform &matrix)
568 {
569     QRasterPaintEngineState *s = state();
570     // FALCON: get rid of this line, see drawImage call below.
571     s->matrix = matrix;
572     QTransform::TransformationType txop = s->matrix.type();
573
574     switch (txop) {
575
576     case QTransform::TxNone:
577         s->flags.int_xform = true;
578         break;
579
580     case QTransform::TxTranslate:
581         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
582                             && qreal(int(s->matrix.dy())) == s->matrix.dy();
583         break;
584
585     case QTransform::TxScale:
586         s->flags.int_xform = qreal(int(s->matrix.dx())) == s->matrix.dx()
587                             && qreal(int(s->matrix.dy())) == s->matrix.dy()
588                             && qreal(int(s->matrix.m11())) == s->matrix.m11()
589                             && qreal(int(s->matrix.m22())) == s->matrix.m22();
590         break;
591
592     default: // shear / perspective...
593         s->flags.int_xform = false;
594         break;
595     }
596
597     s->flags.tx_noshear = qt_scaleForTransform(s->matrix, &s->txscale);
598
599     ensureOutlineMapper();
600
601 #ifdef Q_WS_WIN
602     Q_D(QRasterPaintEngine);
603     d->isPlain45DegreeRotation = false;
604     if (txop >= QTransform::TxRotate) {
605         d->isPlain45DegreeRotation =
606             (qFuzzyIsNull(matrix.m11())
607              && qFuzzyIsNull(matrix.m12() - qreal(1))
608              && qFuzzyIsNull(matrix.m21() + qreal(1))
609              && qFuzzyIsNull(matrix.m22())
610                 )
611             ||
612             (qFuzzyIsNull(matrix.m11() + qreal(1))
613              && qFuzzyIsNull(matrix.m12())
614              && qFuzzyIsNull(matrix.m21())
615              && qFuzzyIsNull(matrix.m22() + qreal(1))
616                 )
617             ||
618             (qFuzzyIsNull(matrix.m11())
619              && qFuzzyIsNull(matrix.m12() + qreal(1))
620              && qFuzzyIsNull(matrix.m21() - qreal(1))
621              && qFuzzyIsNull(matrix.m22())
622                 )
623             ;
624     }
625 #endif
626
627 }
628
629
630
631 QRasterPaintEngineState::~QRasterPaintEngineState()
632 {
633     if (flags.has_clip_ownership)
634         delete clip;
635 }
636
637
638 QRasterPaintEngineState::QRasterPaintEngineState()
639 {
640     stroker = 0;
641
642     fillFlags = 0;
643     strokeFlags = 0;
644     pixmapFlags = 0;
645
646     intOpacity = 256;
647
648     txscale = 1.;
649
650     flags.fast_pen = true;
651     flags.antialiased = false;
652     flags.bilinear = false;
653     flags.fast_text = true;
654     flags.int_xform = true;
655     flags.tx_noshear = true;
656     flags.fast_images = true;
657
658     clip = 0;
659     flags.has_clip_ownership = false;
660
661     dirty = 0;
662 }
663
664 QRasterPaintEngineState::QRasterPaintEngineState(QRasterPaintEngineState &s)
665     : QPainterState(s)
666 {
667     stroker = s.stroker;
668
669     lastBrush = s.lastBrush;
670     brushData = s.brushData;
671     brushData.tempImage = 0;
672
673     lastPen = s.lastPen;
674     penData = s.penData;
675     penData.tempImage = 0;
676
677     fillFlags = s.fillFlags;
678     strokeFlags = s.strokeFlags;
679     pixmapFlags = s.pixmapFlags;
680
681     intOpacity = s.intOpacity;
682
683     txscale = s.txscale;
684
685     flag_bits = s.flag_bits;
686
687     clip = s.clip;
688     flags.has_clip_ownership = false;
689
690     dirty = s.dirty;
691 }
692
693 /*!
694     \internal
695 */
696 QPainterState *QRasterPaintEngine::createState(QPainterState *orig) const
697 {
698     QRasterPaintEngineState *s;
699     if (!orig)
700         s = new QRasterPaintEngineState();
701     else
702         s = new QRasterPaintEngineState(*static_cast<QRasterPaintEngineState *>(orig));
703
704     return s;
705 }
706
707 /*!
708     \internal
709 */
710 void QRasterPaintEngine::setState(QPainterState *s)
711 {
712     Q_D(QRasterPaintEngine);
713     QPaintEngineEx::setState(s);
714     d->rasterBuffer->compositionMode = s->composition_mode;
715 }
716
717 /*!
718     \fn QRasterPaintEngineState *QRasterPaintEngine::state()
719     \internal
720 */
721
722 /*!
723     \fn const QRasterPaintEngineState *QRasterPaintEngine::state() const
724     \internal
725 */
726
727 /*!
728     \internal
729 */
730 void QRasterPaintEngine::penChanged()
731 {
732 #ifdef QT_DEBUG_DRAW
733     qDebug() << "QRasterPaintEngine::penChanged():" << state()->pen;
734 #endif
735     QRasterPaintEngineState *s = state();
736     s->strokeFlags |= DirtyPen;
737     s->dirty |= DirtyPen;
738 }
739
740 /*!
741     \internal
742 */
743 void QRasterPaintEngine::updatePen(const QPen &pen)
744 {
745     Q_D(QRasterPaintEngine);
746     QRasterPaintEngineState *s = state();
747 #ifdef QT_DEBUG_DRAW
748     qDebug() << "QRasterPaintEngine::updatePen():" << s->pen;
749 #endif
750
751     Qt::PenStyle pen_style = qpen_style(pen);
752
753     s->lastPen = pen;
754     s->strokeFlags = 0;
755
756     s->penData.clip = d->clip();
757     s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
758
759     if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
760         || pen.brush().transform().type() >= QTransform::TxNone) {
761         d->updateMatrixData(&s->penData, pen.brush(), s->matrix);
762     }
763
764     // Slightly ugly handling of an uncommon case... We need to change
765     // the pen because it is reused in draw_midpoint to decide dashed
766     // or non-dashed.
767     if (pen_style == Qt::CustomDashLine && pen.dashPattern().size() == 0) {
768         pen_style = Qt::SolidLine;
769         s->lastPen.setStyle(Qt::SolidLine);
770     }
771
772     d->basicStroker.setJoinStyle(qpen_joinStyle(pen));
773     d->basicStroker.setCapStyle(qpen_capStyle(pen));
774     d->basicStroker.setMiterLimit(pen.miterLimit());
775
776     qreal penWidth = qpen_widthf(pen);
777     if (penWidth == 0)
778         d->basicStroker.setStrokeWidth(1);
779     else
780         d->basicStroker.setStrokeWidth(penWidth);
781
782     if(pen_style == Qt::SolidLine) {
783         s->stroker = &d->basicStroker;
784     } else if (pen_style != Qt::NoPen) {
785         if (!d->dashStroker)
786             d->dashStroker.reset(new QDashStroker(&d->basicStroker));
787         if (pen.isCosmetic()) {
788             d->dashStroker->setClipRect(d->deviceRect);
789         } else {
790             // ### I've seen this inverted devrect multiple places now...
791             QRectF clipRect = s->matrix.inverted().mapRect(QRectF(d->deviceRect));
792             d->dashStroker->setClipRect(clipRect);
793         }
794         d->dashStroker->setDashPattern(pen.dashPattern());
795         d->dashStroker->setDashOffset(pen.dashOffset());
796         s->stroker = d->dashStroker.data();
797     } else {
798         s->stroker = 0;
799     }
800
801     s->flags.fast_pen = pen_style > Qt::NoPen
802                   && s->penData.blend
803                   && !s->flags.antialiased
804                   && (penWidth == 0 || (penWidth <= 1
805                                         && (s->matrix.type() <= QTransform::TxTranslate
806                                             || pen.isCosmetic())));
807
808     ensureState(); // needed because of tx_noshear...
809     s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
810
811     s->strokeFlags = 0;
812 }
813
814
815
816 /*!
817     \internal
818 */
819 void QRasterPaintEngine::brushOriginChanged()
820 {
821     QRasterPaintEngineState *s = state();
822 #ifdef QT_DEBUG_DRAW
823     qDebug() << "QRasterPaintEngine::brushOriginChanged()" << s->brushOrigin;
824 #endif
825
826     s->fillFlags |= DirtyBrushOrigin;
827 }
828
829
830 /*!
831     \internal
832 */
833 void QRasterPaintEngine::brushChanged()
834 {
835     QRasterPaintEngineState *s = state();
836 #ifdef QT_DEBUG_DRAW
837     qDebug() << "QRasterPaintEngine::brushChanged():" << s->brush;
838 #endif
839     s->fillFlags |= DirtyBrush;
840 }
841
842
843
844
845 /*!
846     \internal
847 */
848 void QRasterPaintEngine::updateBrush(const QBrush &brush)
849 {
850 #ifdef QT_DEBUG_DRAW
851     qDebug() << "QRasterPaintEngine::updateBrush()" << brush;
852 #endif
853     Q_D(QRasterPaintEngine);
854     QRasterPaintEngineState *s = state();
855     // must set clip prior to setup, as setup uses it...
856     s->brushData.clip = d->clip();
857     s->brushData.setup(brush, s->intOpacity, s->composition_mode);
858     if (s->fillFlags & DirtyTransform
859         || brush.transform().type() >= QTransform::TxNone)
860         d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
861     s->lastBrush = brush;
862     s->fillFlags = 0;
863 }
864
865 void QRasterPaintEngine::updateOutlineMapper()
866 {
867     Q_D(QRasterPaintEngine);
868     d->outlineMapper->setMatrix(state()->matrix);
869 }
870
871 void QRasterPaintEngine::updateState()
872 {
873     QRasterPaintEngineState *s = state();
874
875     if (s->dirty & DirtyTransform)
876         updateMatrix(s->matrix);
877
878     if (s->dirty & (DirtyPen|DirtyCompositionMode)) {
879         const QPainter::CompositionMode mode = s->composition_mode;
880         s->flags.fast_text = (s->penData.type == QSpanData::Solid)
881                        && (mode == QPainter::CompositionMode_Source
882                            || (mode == QPainter::CompositionMode_SourceOver
883                                && qAlpha(s->penData.solid.color) == 255));
884     }
885
886     s->dirty = 0;
887 }
888
889
890 /*!
891     \internal
892 */
893 void QRasterPaintEngine::opacityChanged()
894 {
895     QRasterPaintEngineState *s = state();
896
897 #ifdef QT_DEBUG_DRAW
898     qDebug() << "QRasterPaintEngine::opacityChanged()" << s->opacity;
899 #endif
900
901     s->fillFlags |= DirtyOpacity;
902     s->strokeFlags |= DirtyOpacity;
903     s->pixmapFlags |= DirtyOpacity;
904     s->intOpacity = (int) (s->opacity * 256);
905 }
906
907 /*!
908     \internal
909 */
910 void QRasterPaintEngine::compositionModeChanged()
911 {
912     Q_D(QRasterPaintEngine);
913     QRasterPaintEngineState *s = state();
914
915 #ifdef QT_DEBUG_DRAW
916     qDebug() << "QRasterPaintEngine::compositionModeChanged()" << s->composition_mode;
917 #endif
918
919     s->fillFlags |= DirtyCompositionMode;
920     s->dirty |= DirtyCompositionMode;
921
922     s->strokeFlags |= DirtyCompositionMode;
923     d->rasterBuffer->compositionMode = s->composition_mode;
924
925     d->recalculateFastImages();
926 }
927
928 /*!
929     \internal
930 */
931 void QRasterPaintEngine::renderHintsChanged()
932 {
933     QRasterPaintEngineState *s = state();
934
935 #ifdef QT_DEBUG_DRAW
936     qDebug() << "QRasterPaintEngine::renderHintsChanged()" << hex << s->renderHints;
937 #endif
938
939     bool was_aa = s->flags.antialiased;
940     bool was_bilinear = s->flags.bilinear;
941
942     s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
943     s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
944
945     if (was_aa != s->flags.antialiased)
946         s->strokeFlags |= DirtyHints;
947
948     if (was_bilinear != s->flags.bilinear) {
949         s->strokeFlags |= DirtyPen;
950         s->fillFlags |= DirtyBrush;
951     }
952
953     Q_D(QRasterPaintEngine);
954     d->recalculateFastImages();
955 }
956
957 /*!
958     \internal
959 */
960 void QRasterPaintEngine::transformChanged()
961 {
962     QRasterPaintEngineState *s = state();
963
964 #ifdef QT_DEBUG_DRAW
965     qDebug() << "QRasterPaintEngine::transformChanged()" << s->matrix;
966 #endif
967
968     s->fillFlags |= DirtyTransform;
969     s->strokeFlags |= DirtyTransform;
970
971     s->dirty |= DirtyTransform;
972
973     Q_D(QRasterPaintEngine);
974     d->recalculateFastImages();
975 }
976
977 /*!
978     \internal
979 */
980 void QRasterPaintEngine::clipEnabledChanged()
981 {
982     QRasterPaintEngineState *s = state();
983
984 #ifdef QT_DEBUG_DRAW
985     qDebug() << "QRasterPaintEngine::clipEnabledChanged()" << s->clipEnabled;
986 #endif
987
988     if (s->clip) {
989         s->clip->enabled = s->clipEnabled;
990         s->fillFlags |= DirtyClipEnabled;
991         s->strokeFlags |= DirtyClipEnabled;
992         s->pixmapFlags |= DirtyClipEnabled;
993     }
994 }
995
996 #ifdef Q_WS_QWS
997 void QRasterPaintEnginePrivate::prepare(QCustomRasterPaintDevice *device)
998 {
999     rasterBuffer->prepare(device);
1000 }
1001 #endif
1002
1003 void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
1004                                           const QImage &img,
1005                                           SrcOverBlendFunc func,
1006                                           const QRect &clip,
1007                                           int alpha,
1008                                           const QRect &sr)
1009 {
1010     if (alpha == 0 || !clip.isValid())
1011         return;
1012
1013     Q_ASSERT(img.depth() >= 8);
1014
1015     int srcBPL = img.bytesPerLine();
1016     const uchar *srcBits = img.bits();
1017     int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
1018     int iw = img.width();
1019     int ih = img.height();
1020
1021     if (!sr.isEmpty()) {
1022         iw = sr.width();
1023         ih = sr.height();
1024         // Adjust the image according to the source offset...
1025         srcBits += ((sr.y() * srcBPL) + sr.x() * srcSize);
1026     }
1027
1028     // adapt the x parameters
1029     int x = qRound(pt.x());
1030     int cx1 = clip.x();
1031     int cx2 = clip.x() + clip.width();
1032     if (x < cx1) {
1033         int d = cx1 - x;
1034         srcBits += srcSize * d;
1035         iw -= d;
1036         x = cx1;
1037     }
1038     if (x + iw > cx2) {
1039         int d = x + iw - cx2;
1040         iw -= d;
1041     }
1042     if (iw <= 0)
1043         return;
1044
1045     // adapt the y paremeters...
1046     int cy1 = clip.y();
1047     int cy2 = clip.y() + clip.height();
1048     int y = qRound(pt.y());
1049     if (y < cy1) {
1050         int d = cy1 - y;
1051         srcBits += srcBPL * d;
1052         ih -= d;
1053         y = cy1;
1054     }
1055     if (y + ih > cy2) {
1056         int d = y + ih - cy2;
1057         ih -= d;
1058     }
1059     if (ih <= 0)
1060         return;
1061
1062     // call the blend function...
1063     int dstSize = rasterBuffer->bytesPerPixel();
1064     int dstBPL = rasterBuffer->bytesPerLine();
1065     func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
1066          srcBits, srcBPL,
1067          iw, ih,
1068          alpha);
1069 }
1070
1071
1072 void QRasterPaintEnginePrivate::systemStateChanged()
1073 {
1074     QRect clipRect(0, 0,
1075             qMin(QT_RASTER_COORD_LIMIT, device->width()),
1076             qMin(QT_RASTER_COORD_LIMIT, device->height()));
1077
1078     if (!systemClip.isEmpty()) {
1079         QRegion clippedDeviceRgn = systemClip & clipRect;
1080         deviceRect = clippedDeviceRgn.boundingRect();
1081         baseClip->setClipRegion(clippedDeviceRgn);
1082     } else {
1083         deviceRect = clipRect;
1084         baseClip->setClipRect(deviceRect);
1085     }
1086 #ifdef QT_DEBUG_DRAW
1087     qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
1088 #endif
1089
1090     exDeviceRect = deviceRect;
1091
1092     Q_Q(QRasterPaintEngine);
1093     q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1094     q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1095     q->state()->pixmapFlags |= QPaintEngine::DirtyClipRegion;
1096 }
1097
1098 void QRasterPaintEnginePrivate::updateMatrixData(QSpanData *spanData, const QBrush &b, const QTransform &m)
1099 {
1100     if (b.d->style == Qt::NoBrush || b.d->style == Qt::SolidPattern)
1101         return;
1102
1103     Q_Q(QRasterPaintEngine);
1104     bool bilinear = q->state()->flags.bilinear;
1105
1106     if (b.d->transform.type() > QTransform::TxNone) { // FALCON: optimize
1107         spanData->setupMatrix(b.transform() * m, bilinear);
1108     } else {
1109         if (m.type() <= QTransform::TxTranslate) {
1110             // specialize setupMatrix for translation matrices
1111             // to avoid needless matrix inversion
1112             spanData->m11 = 1;
1113             spanData->m12 = 0;
1114             spanData->m13 = 0;
1115             spanData->m21 = 0;
1116             spanData->m22 = 1;
1117             spanData->m23 = 0;
1118             spanData->m33 = 1;
1119             spanData->dx = -m.dx();
1120             spanData->dy = -m.dy();
1121             spanData->txop = m.type();
1122             spanData->bilinear = bilinear;
1123             spanData->fast_matrix = qAbs(m.dx()) < 1e4 && qAbs(m.dy()) < 1e4;
1124             spanData->adjustSpanMethods();
1125         } else {
1126             spanData->setupMatrix(m, bilinear);
1127         }
1128     }
1129 }
1130
1131 // #define QT_CLIPPING_RATIOS
1132
1133 #ifdef QT_CLIPPING_RATIOS
1134 int rectClips;
1135 int regionClips;
1136 int totalClips;
1137
1138 static void checkClipRatios(QRasterPaintEnginePrivate *d)
1139 {
1140     if (d->clip()->hasRectClip)
1141         rectClips++;
1142     if (d->clip()->hasRegionClip)
1143         regionClips++;
1144     totalClips++;
1145
1146     if ((totalClips % 5000) == 0) {
1147         printf("Clipping ratio: rectangular=%f%%, region=%f%%, complex=%f%%\n",
1148                rectClips * 100.0 / (qreal) totalClips,
1149                regionClips * 100.0 / (qreal) totalClips,
1150                (totalClips - rectClips - regionClips) * 100.0 / (qreal) totalClips);
1151         totalClips = 0;
1152         rectClips = 0;
1153         regionClips = 0;
1154     }
1155
1156 }
1157 #endif
1158
1159 static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1160 {
1161     if (s->flags.has_clip_ownership)
1162         delete s->clip;
1163     s->clip = 0;
1164     s->flags.has_clip_ownership = false;
1165 }
1166
1167 static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1168 {
1169     s->fillFlags |= QPaintEngine::DirtyClipPath;
1170     s->strokeFlags |= QPaintEngine::DirtyClipPath;
1171     s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1172
1173     d->solid_color_filler.clip = d->clip();
1174     d->solid_color_filler.adjustSpanMethods();
1175
1176 #ifdef QT_DEBUG_DRAW
1177     dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1178 #endif
1179
1180 }
1181
1182
1183 /*!
1184     \internal
1185 */
1186 void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
1187 {
1188 #ifdef QT_DEBUG_DRAW
1189     qDebug() << "QRasterPaintEngine::clip(): " << path << op;
1190
1191     if (path.elements()) {
1192         for (int i=0; i<path.elementCount(); ++i) {
1193             qDebug() << " - " << path.elements()[i]
1194                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1195         }
1196     } else {
1197         for (int i=0; i<path.elementCount(); ++i) {
1198             qDebug() << " ---- "
1199                      << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1200         }
1201     }
1202 #endif
1203
1204     Q_D(QRasterPaintEngine);
1205     QRasterPaintEngineState *s = state();
1206
1207     const qreal *points = path.points();
1208     const QPainterPath::ElementType *types = path.elements();
1209
1210     // There are some cases that are not supported by clip(QRect)
1211     if (op != Qt::UniteClip && (op != Qt::IntersectClip || !s->clip
1212                                 || s->clip->hasRectClip || s->clip->hasRegionClip)) {
1213         if (s->matrix.type() <= QTransform::TxTranslate
1214             && ((path.shape() == QVectorPath::RectangleHint)
1215                 || (isRect(points, path.elementCount())
1216                     && (!types || (types[0] == QPainterPath::MoveToElement
1217                                    && types[1] == QPainterPath::LineToElement
1218                                    && types[2] == QPainterPath::LineToElement
1219                                    && types[3] == QPainterPath::LineToElement))))) {
1220 #ifdef QT_DEBUG_DRAW
1221             qDebug() << " --- optimizing vector clip to rect clip...";
1222 #endif
1223
1224             QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1225             clip(r.toRect(), op);
1226             return;
1227         }
1228     }
1229
1230     if (op == Qt::NoClip) {
1231         qrasterpaintengine_state_setNoClip(s);
1232
1233     } else {
1234         QClipData *base = d->baseClip.data();
1235
1236         // Intersect with current clip when available...
1237         if (op == Qt::IntersectClip && s->clip)
1238             base = s->clip;
1239
1240         // We always intersect, except when there is nothing to
1241         // intersect with, in which case we simplify the operation to
1242         // a replace...
1243         Qt::ClipOperation isectOp = Qt::IntersectClip;
1244         if (base == 0)
1245             isectOp = Qt::ReplaceClip;
1246
1247         QClipData *newClip = new QClipData(d->rasterBuffer->height());
1248         newClip->initialize();
1249         ClipData clipData = { base, newClip, isectOp };
1250         ensureOutlineMapper();
1251         d->rasterize(d->outlineMapper->convertPath(path), qt_span_clip, &clipData, 0);
1252
1253         newClip->fixup();
1254
1255         if (op == Qt::UniteClip) {
1256             // merge clips
1257             QClipData *result = new QClipData(d->rasterBuffer->height());
1258             QClipData *current = s->clip ? s->clip : new QClipData(d->rasterBuffer->height());
1259             qt_merge_clip(current, newClip, result);
1260             result->fixup();
1261             delete newClip;
1262             if (!s->clip)
1263                 delete current;
1264             newClip = result;
1265         }
1266
1267         if (s->flags.has_clip_ownership)
1268             delete s->clip;
1269
1270         s->clip = newClip;
1271         s->flags.has_clip_ownership = true;
1272     }
1273     qrasterpaintengine_dirty_clip(d, s);
1274 }
1275
1276
1277
1278 /*!
1279     \internal
1280 */
1281 void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
1282 {
1283 #ifdef QT_DEBUG_DRAW
1284     qDebug() << "QRasterPaintEngine::clip(): " << rect << op;
1285 #endif
1286
1287     Q_D(QRasterPaintEngine);
1288     QRasterPaintEngineState *s = state();
1289
1290     if (op == Qt::NoClip) {
1291         qrasterpaintengine_state_setNoClip(s);
1292
1293     } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1294         QPaintEngineEx::clip(rect, op);
1295         return;
1296
1297     } else if (op == Qt::ReplaceClip || s->clip == 0) {
1298
1299         // No current clip, hence we intersect with sysclip and be
1300         // done with it...
1301         QRect clipRect = s->matrix.mapRect(rect) & d->deviceRect;
1302         QRegion clipRegion = systemClip();
1303         QClipData *clip = new QClipData(d->rasterBuffer->height());
1304
1305         if (clipRegion.isEmpty())
1306             clip->setClipRect(clipRect);
1307         else
1308             clip->setClipRegion(clipRegion & clipRect);
1309
1310         if (s->flags.has_clip_ownership)
1311             delete s->clip;
1312
1313         s->clip = clip;
1314         s->clip->enabled = true;
1315         s->flags.has_clip_ownership = true;
1316
1317     } else { // intersect clip with current clip
1318         QClipData *base = s->clip;
1319
1320         Q_ASSERT(base);
1321         if (base->hasRectClip || base->hasRegionClip) {
1322             QRect clipRect = s->matrix.mapRect(rect) & d->deviceRect;
1323             if (!s->flags.has_clip_ownership) {
1324                 s->clip = new QClipData(d->rasterBuffer->height());
1325                 s->flags.has_clip_ownership = true;
1326             }
1327             if (base->hasRectClip)
1328                 s->clip->setClipRect(base->clipRect & clipRect);
1329             else
1330                 s->clip->setClipRegion(base->clipRegion & clipRect);
1331             s->clip->enabled = true;
1332         } else {
1333             QPaintEngineEx::clip(rect, op);
1334             return;
1335         }
1336     }
1337     qrasterpaintengine_dirty_clip(d, s);
1338 }
1339
1340
1341 /*!
1342     \internal
1343 */
1344 void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1345 {
1346 #ifdef QT_DEBUG_DRAW
1347     qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1348 #endif
1349
1350     Q_D(QRasterPaintEngine);
1351
1352     if (region.rectCount() == 1) {
1353         clip(region.boundingRect(), op);
1354         return;
1355     }
1356
1357     QRasterPaintEngineState *s = state();
1358     const QClipData *clip = d->clip();
1359     const QClipData *baseClip = d->baseClip.data();
1360
1361     if (op == Qt::NoClip) {
1362         qrasterpaintengine_state_setNoClip(s);
1363     } else if (s->matrix.type() > QTransform::TxScale
1364                || op == Qt::UniteClip
1365                || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1366                || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1367         QPaintEngineEx::clip(region, op);
1368     } else {
1369         const QClipData *curClip;
1370         QClipData *newClip;
1371
1372         if (op == Qt::IntersectClip)
1373             curClip = clip;
1374         else
1375             curClip = baseClip;
1376
1377         if (s->flags.has_clip_ownership) {
1378             newClip = s->clip;
1379             Q_ASSERT(newClip);
1380         } else {
1381             newClip = new QClipData(d->rasterBuffer->height());
1382             s->clip = newClip;
1383             s->flags.has_clip_ownership = true;
1384         }
1385
1386         QRegion r = s->matrix.map(region);
1387         if (curClip->hasRectClip)
1388             newClip->setClipRegion(r & curClip->clipRect);
1389         else if (curClip->hasRegionClip)
1390             newClip->setClipRegion(r & curClip->clipRegion);
1391
1392         qrasterpaintengine_dirty_clip(d, s);
1393     }
1394 }
1395
1396 /*!
1397     \internal
1398 */
1399 void QRasterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
1400 {
1401 #ifdef QT_DEBUG_DRAW
1402     qDebug() << " --- fillPath, bounds=" << path.boundingRect();
1403 #endif
1404
1405     if (!fillData->blend)
1406         return;
1407
1408     Q_D(QRasterPaintEngine);
1409
1410     const QRectF controlPointRect = path.controlPointRect();
1411
1412     QRasterPaintEngineState *s = state();
1413     const QRect deviceRect = s->matrix.mapRect(controlPointRect).toRect();
1414     ProcessSpans blend = d->getBrushFunc(deviceRect, fillData);
1415     const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1416                           || deviceRect.right() > QT_RASTER_COORD_LIMIT
1417                           || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1418                           || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1419
1420     if (!s->flags.antialiased && !do_clip) {
1421         d->initializeRasterizer(fillData);
1422         d->rasterizer->rasterize(path * s->matrix, path.fillRule());
1423         return;
1424     }
1425
1426     ensureOutlineMapper();
1427     d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1428 }
1429
1430 static void fillRect_normalized(const QRect &r, QSpanData *data,
1431                                 QRasterPaintEnginePrivate *pe)
1432 {
1433     int x1, x2, y1, y2;
1434
1435     bool rectClipped = true;
1436
1437     if (data->clip) {
1438         x1 = qMax(r.x(), data->clip->xmin);
1439         x2 = qMin(r.x() + r.width(), data->clip->xmax);
1440         y1 = qMax(r.y(), data->clip->ymin);
1441         y2 = qMin(r.y() + r.height(), data->clip->ymax);
1442         rectClipped = data->clip->hasRectClip;
1443
1444     } else if (pe) {
1445         x1 = qMax(r.x(), pe->deviceRect.x());
1446         x2 = qMin(r.x() + r.width(), pe->deviceRect.x() + pe->deviceRect.width());
1447         y1 = qMax(r.y(), pe->deviceRect.y());
1448         y2 = qMin(r.y() + r.height(), pe->deviceRect.y() + pe->deviceRect.height());
1449     } else {
1450         x1 = qMax(r.x(), 0);
1451         x2 = qMin(r.x() + r.width(), data->rasterBuffer->width());
1452         y1 = qMax(r.y(), 0);
1453         y2 = qMin(r.y() + r.height(), data->rasterBuffer->height());
1454     }
1455
1456     if (x2 <= x1 || y2 <= y1)
1457         return;
1458
1459     const int width = x2 - x1;
1460     const int height = y2 - y1;
1461
1462     bool isUnclipped = rectClipped
1463                        || (pe && pe->isUnclipped_normalized(QRect(x1, y1, width, height)));
1464
1465     if (pe && isUnclipped) {
1466         const QPainter::CompositionMode mode = pe->rasterBuffer->compositionMode;
1467
1468         if (data->fillRect && (mode == QPainter::CompositionMode_Source
1469                                || (mode == QPainter::CompositionMode_SourceOver
1470                                    && qAlpha(data->solid.color) == 255)))
1471         {
1472             data->fillRect(data->rasterBuffer, x1, y1, width, height,
1473                            data->solid.color);
1474             return;
1475         }
1476     }
1477
1478     ProcessSpans blend = isUnclipped ? data->unclipped_blend : data->blend;
1479
1480     const int nspans = 256;
1481     QT_FT_Span spans[nspans];
1482
1483     Q_ASSERT(data->blend);
1484     int y = y1;
1485     while (y < y2) {
1486         int n = qMin(nspans, y2 - y);
1487         int i = 0;
1488         while (i < n) {
1489             spans[i].x = x1;
1490             spans[i].len = width;
1491             spans[i].y = y + i;
1492             spans[i].coverage = 255;
1493             ++i;
1494         }
1495
1496         blend(n, spans, data);
1497         y += n;
1498     }
1499 }
1500
1501 /*!
1502     \reimp
1503 */
1504 void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
1505 {
1506 #ifdef QT_DEBUG_DRAW
1507     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1508 #endif
1509     Q_D(QRasterPaintEngine);
1510     QRasterPaintEngineState *s = state();
1511
1512     // Fill
1513     ensureBrush();
1514     if (s->brushData.blend) {
1515         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxTranslate) {
1516             const QRect *r = rects;
1517             const QRect *lastRect = rects + rectCount;
1518
1519             int offset_x = int(s->matrix.dx());
1520             int offset_y = int(s->matrix.dy());
1521             while (r < lastRect) {
1522                 QRect rect = r->normalized();
1523                 QRect rr = rect.translated(offset_x, offset_y);
1524                 fillRect_normalized(rr, &s->brushData, d);
1525                 ++r;
1526             }
1527         } else {
1528             QRectVectorPath path;
1529             for (int i=0; i<rectCount; ++i) {
1530                 path.set(rects[i]);
1531                 fill(path, s->brush);
1532             }
1533         }
1534     }
1535
1536     ensurePen();
1537     if (s->penData.blend) {
1538         if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
1539             const QRect *r = rects;
1540             const QRect *lastRect = rects + rectCount;
1541             while (r < lastRect) {
1542                 int left = r->x();
1543                 int right = r->x() + r->width();
1544                 int top = r->y();
1545                 int bottom = r->y() + r->height();
1546
1547 #ifdef Q_WS_MAC
1548                 int pts[] = { top, left,
1549                               top, right,
1550                               bottom, right,
1551                               bottom, left };
1552 #else
1553                 int pts[] = { left, top,
1554                               right, top,
1555                               right, bottom,
1556                               left, bottom };
1557 #endif
1558
1559                 strokePolygonCosmetic((QPoint *) pts, 4, WindingMode);
1560                 ++r;
1561             }
1562         } else {
1563             QRectVectorPath path;
1564             for (int i = 0; i < rectCount; ++i) {
1565                 path.set(rects[i]);
1566                 stroke(path, s->pen);
1567             }
1568         }
1569     }
1570 }
1571
1572 /*!
1573     \reimp
1574 */
1575 void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
1576 {
1577 #ifdef QT_DEBUG_DRAW
1578     qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
1579 #endif
1580 #ifdef QT_FAST_SPANS
1581     Q_D(QRasterPaintEngine);
1582     QRasterPaintEngineState *s = state();
1583
1584     ensureState();
1585
1586     if (s->flags.tx_noshear) {
1587         ensureBrush();
1588         if (s->brushData.blend) {
1589             d->initializeRasterizer(&s->brushData);
1590             for (int i = 0; i < rectCount; ++i) {
1591                 const QRectF &rect = rects[i].normalized();
1592                 if (rect.isEmpty())
1593                     continue;
1594                 const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
1595                 const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
1596                 d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
1597             }
1598         }
1599
1600         ensurePen();
1601         if (s->penData.blend) {
1602             qreal width = s->pen.isCosmetic()
1603                           ? (s->lastPen.widthF() == 0 ? 1 : s->lastPen.widthF())
1604                           : s->lastPen.widthF() * s->txscale;
1605
1606             if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
1607                 for (int i = 0; i < rectCount; ++i) {
1608                     const QRectF &r = rects[i];
1609                     qreal left = r.x();
1610                     qreal right = r.x() + r.width();
1611                     qreal top = r.y();
1612                     qreal bottom = r.y() + r.height();
1613                     qreal pts[] = { left, top,
1614                                     right, top,
1615                                     right, bottom,
1616                                     left, bottom };
1617                     strokePolygonCosmetic((QPointF *) pts, 4, WindingMode);
1618                 }
1619             } else if (width <= 1 && qpen_style(s->lastPen) == Qt::SolidLine) {
1620                 d->initializeRasterizer(&s->penData);
1621
1622                 for (int i = 0; i < rectCount; ++i) {
1623                     const QRectF &rect = rects[i].normalized();
1624                     if (rect.isEmpty()) {
1625                         qreal pts[] = { rect.left(), rect.top(), rect.right(), rect.bottom() };
1626                         QVectorPath vp(pts, 2, 0, QVectorPath::LinesHint);
1627                         QPaintEngineEx::stroke(vp, s->lastPen);
1628                     } else {
1629                         const QPointF tl = s->matrix.map(rect.topLeft());
1630                         const QPointF tr = s->matrix.map(rect.topRight());
1631                         const QPointF bl = s->matrix.map(rect.bottomLeft());
1632                         const QPointF br = s->matrix.map(rect.bottomRight());
1633                         const qreal w = width / (rect.width() * s->txscale);
1634                         const qreal h = width / (rect.height() * s->txscale);
1635                         d->rasterizer->rasterizeLine(tl, tr, w); // top
1636                         d->rasterizer->rasterizeLine(bl, br, w); // bottom
1637                         d->rasterizer->rasterizeLine(bl, tl, h); // left
1638                         d->rasterizer->rasterizeLine(br, tr, h); // right
1639                     }
1640                 }
1641             } else {
1642                 for (int i = 0; i < rectCount; ++i) {
1643                     const QRectF &r = rects[i];
1644                     qreal left = r.x();
1645                     qreal right = r.x() + r.width();
1646                     qreal top = r.y();
1647                     qreal bottom = r.y() + r.height();
1648                     qreal pts[] = { left, top,
1649                                     right, top,
1650                                     right, bottom,
1651                                     left, bottom,
1652                                     left, top };
1653                     QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint);
1654                     QPaintEngineEx::stroke(vp, s->lastPen);
1655                 }
1656             }
1657         }
1658
1659         return;
1660     }
1661 #endif // QT_FAST_SPANS
1662     QPaintEngineEx::drawRects(rects, rectCount);
1663 }
1664
1665
1666 /*!
1667     \internal
1668 */
1669 void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
1670 {
1671     QRasterPaintEngineState *s = state();
1672     ensurePen(pen);
1673     if (!s->penData.blend)
1674         return;
1675
1676     if (s->flags.fast_pen && !path.isCurved()
1677         && s->lastPen.brush().isOpaque()) {
1678         int count = path.elementCount();
1679         QPointF *points = (QPointF *) path.points();
1680         const QPainterPath::ElementType *types = path.elements();
1681         if (types) {
1682             int first = 0;
1683             int last;
1684             while (first < count) {
1685                 while (first < count && types[first] != QPainterPath::MoveToElement) ++first;
1686                 last = first + 1;
1687                 while (last < count && types[last] == QPainterPath::LineToElement) ++last;
1688                 strokePolygonCosmetic(points + first, last - first,
1689                                       path.hasImplicitClose() && last == count // only close last one..
1690                                       ? WindingMode
1691                                       : PolylineMode);
1692                 first = last;
1693             }
1694         } else {
1695             strokePolygonCosmetic(points, count,
1696                                   path.hasImplicitClose()
1697                                   ? WindingMode
1698                                   : PolylineMode);
1699         }
1700
1701     } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1702         qreal width = s->lastPen.isCosmetic()
1703                       ? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
1704                       : qpen_widthf(s->lastPen) * s->txscale;
1705         int dashIndex = 0;
1706         qreal dashOffset = s->lastPen.dashOffset();
1707         bool inDash = true;
1708         qreal patternLength = 0;
1709         const QVector<qreal> pattern = s->lastPen.dashPattern();
1710         for (int i = 0; i < pattern.size(); ++i)
1711             patternLength += pattern.at(i);
1712
1713         if (patternLength > 0) {
1714             int n = qFloor(dashOffset / patternLength);
1715             dashOffset -= n * patternLength;
1716             while (dashOffset >= pattern.at(dashIndex)) {
1717                 dashOffset -= pattern.at(dashIndex);
1718                 if (++dashIndex >= pattern.size())
1719                     dashIndex = 0;
1720                 inDash = !inDash;
1721             }
1722         }
1723
1724         Q_D(QRasterPaintEngine);
1725         d->initializeRasterizer(&s->penData);
1726         int lineCount = path.elementCount() / 2;
1727         const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1728
1729         for (int i = 0; i < lineCount; ++i) {
1730             if (lines[i].p1() == lines[i].p2()) {
1731                 if (s->lastPen.capStyle() != Qt::FlatCap) {
1732                     QPointF p = lines[i].p1();
1733                     QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
1734                                                        QPointF(p.x() + width*0.5, p.y())));
1735                     d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1);
1736                 }
1737                 continue;
1738             }
1739
1740             const QLineF line = s->matrix.map(lines[i]);
1741             if (qpen_style(s->lastPen) == Qt::SolidLine) {
1742                 d->rasterizer->rasterizeLine(line.p1(), line.p2(),
1743                                             width / line.length(),
1744                                             s->lastPen.capStyle() == Qt::SquareCap);
1745             } else {
1746                 d->rasterizeLine_dashed(line, width,
1747                                         &dashIndex, &dashOffset, &inDash);
1748             }
1749         }
1750     }
1751     else
1752         QPaintEngineEx::stroke(path, pen);
1753 }
1754
1755 static inline QRect toNormalizedFillRect(const QRectF &rect)
1756 {
1757     int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1758     int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1759     int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1760     int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1761
1762     if (x2 < x1)
1763         qSwap(x1, x2);
1764     if (y2 < y1)
1765         qSwap(y1, y2);
1766
1767     return QRect(x1, y1, x2 - x1, y2 - y1);
1768 }
1769
1770 /*!
1771     \internal
1772 */
1773 void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
1774 {
1775     if (path.isEmpty())
1776         return;
1777 #ifdef QT_DEBUG_DRAW
1778     QRectF rf = path.controlPointRect();
1779     qDebug() << "QRasterPaintEngine::fill(): "
1780              << "size=" << path.elementCount()
1781              << ", hints=" << hex << path.hints()
1782              << rf << brush;
1783 #endif
1784
1785     Q_D(QRasterPaintEngine);
1786     QRasterPaintEngineState *s = state();
1787
1788     ensureBrush(brush);
1789     if (!s->brushData.blend)
1790         return;
1791
1792     if (path.shape() == QVectorPath::RectangleHint) {
1793         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1794             const qreal *p = path.points();
1795             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1796             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1797             fillRect_normalized(toNormalizedFillRect(QRectF(tl, br)), &s->brushData, d);
1798             return;
1799         }
1800         ensureState();
1801         if (s->flags.tx_noshear) {
1802             d->initializeRasterizer(&s->brushData);
1803             // ### Is normalizing really nessesary here?
1804             const qreal *p = path.points();
1805             QRectF r = QRectF(p[0], p[1], p[2] - p[0], p[7] - p[1]).normalized();
1806             if (!r.isEmpty()) {
1807                 const QPointF a = s->matrix.map((r.topLeft() + r.bottomLeft()) * 0.5f);
1808                 const QPointF b = s->matrix.map((r.topRight() + r.bottomRight()) * 0.5f);
1809                 d->rasterizer->rasterizeLine(a, b, r.height() / r.width());
1810             }
1811             return;
1812         }
1813     }
1814
1815     if (path.shape() == QVectorPath::EllipseHint) {
1816         if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
1817             const qreal *p = path.points();
1818             QPointF tl = QPointF(p[0], p[1]) * s->matrix;
1819             QPointF br = QPointF(p[4], p[5]) * s->matrix;
1820             QRectF r = s->matrix.mapRect(QRectF(tl, br));
1821
1822             ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
1823             ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
1824             const QRect brect = QRect(int(r.x()), int(r.y()),
1825                                       int_dim(r.x(), r.width()),
1826                                       int_dim(r.y(), r.height()));
1827             if (brect == r) {
1828                 drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
1829                                        &s->penData, &s->brushData);
1830                 return;
1831             }
1832         }
1833     }
1834
1835     // ### Optimize for non transformed ellipses and rectangles...
1836     QRectF cpRect = path.controlPointRect();
1837     const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1838     ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1839
1840         // ### Falcon
1841 //         const bool do_clip = (deviceRect.left() < -QT_RASTER_COORD_LIMIT
1842 //                               || deviceRect.right() > QT_RASTER_COORD_LIMIT
1843 //                               || deviceRect.top() < -QT_RASTER_COORD_LIMIT
1844 //                               || deviceRect.bottom() > QT_RASTER_COORD_LIMIT);
1845
1846         // ### Falonc: implement....
1847 //         if (!s->flags.antialiased && !do_clip) {
1848 //             d->initializeRasterizer(&s->brushData);
1849 //             d->rasterizer->rasterize(path * d->matrix, path.fillRule());
1850 //             return;
1851 //         }
1852
1853     ensureOutlineMapper();
1854     d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1855 }
1856
1857 void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1858 {
1859     Q_D(QRasterPaintEngine);
1860     QRasterPaintEngineState *s = state();
1861
1862     if (!s->flags.antialiased) {
1863         uint txop = s->matrix.type();
1864         if (txop == QTransform::TxNone) {
1865             fillRect_normalized(toNormalizedFillRect(r), data, d);
1866             return;
1867         } else if (txop == QTransform::TxTranslate) {
1868             const QRect rr = toNormalizedFillRect(r.translated(s->matrix.dx(), s->matrix.dy()));
1869             fillRect_normalized(rr, data, d);
1870             return;
1871         } else if (txop == QTransform::TxScale) {
1872             const QRect rr = toNormalizedFillRect(s->matrix.mapRect(r));
1873             fillRect_normalized(rr, data, d);
1874             return;
1875         }
1876     }
1877     ensureState();
1878     if (s->flags.tx_noshear) {
1879         d->initializeRasterizer(data);
1880         QRectF nr = r.normalized();
1881         if (!nr.isEmpty()) {
1882             const QPointF a = s->matrix.map((nr.topLeft() + nr.bottomLeft()) * 0.5f);
1883             const QPointF b = s->matrix.map((nr.topRight() + nr.bottomRight()) * 0.5f);
1884             d->rasterizer->rasterizeLine(a, b, nr.height() / nr.width());
1885         }
1886         return;
1887     }
1888
1889     QPainterPath path;
1890     path.addRect(r);
1891     ensureOutlineMapper();
1892     fillPath(path, data);
1893 }
1894
1895 /*!
1896     \reimp
1897 */
1898 void QRasterPaintEngine::fillRect(const QRectF &r, const QBrush &brush)
1899 {
1900 #ifdef QT_DEBUG_DRAW
1901     qDebug() << "QRasterPaintEngine::fillRecct(): " << r << brush;
1902 #endif
1903     QRasterPaintEngineState *s = state();
1904
1905     ensureBrush(brush);
1906     if (!s->brushData.blend)
1907         return;
1908
1909     fillRect(r, &s->brushData);
1910 }
1911
1912 /*!
1913     \reimp
1914 */
1915 void QRasterPaintEngine::fillRect(const QRectF &r, const QColor &color)
1916 {
1917 #ifdef QT_DEBUG_DRAW
1918     qDebug() << "QRasterPaintEngine::fillRect(): " << r << color;
1919 #endif
1920     Q_D(QRasterPaintEngine);
1921     QRasterPaintEngineState *s = state();
1922
1923     d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1924     if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1925         && s->composition_mode == QPainter::CompositionMode_SourceOver) {
1926         return;
1927     }
1928     d->solid_color_filler.clip = d->clip();
1929     d->solid_color_filler.adjustSpanMethods();
1930     fillRect(r, &d->solid_color_filler);
1931 }
1932
1933 static inline bool isAbove(const QPointF *a, const QPointF *b)
1934 {
1935     return a->y() < b->y();
1936 }
1937
1938 static bool splitPolygon(const QPointF *points, int pointCount, QVector<QPointF> *upper, QVector<QPointF> *lower)
1939 {
1940     Q_ASSERT(upper);
1941     Q_ASSERT(lower);
1942
1943     Q_ASSERT(pointCount >= 2);
1944
1945     QVector<const QPointF *> sorted;
1946     sorted.reserve(pointCount);
1947
1948     upper->reserve(pointCount * 3 / 4);
1949     lower->reserve(pointCount * 3 / 4);
1950
1951     for (int i = 0; i < pointCount; ++i)
1952         sorted << points + i;
1953
1954     qSort(sorted.begin(), sorted.end(), isAbove);
1955
1956     qreal splitY = sorted.at(sorted.size() / 2)->y();
1957
1958     const QPointF *end = points + pointCount;
1959     const QPointF *last = end - 1;
1960
1961     QVector<QPointF> *bin[2] = { upper, lower };
1962
1963     for (const QPointF *p = points; p < end; ++p) {
1964         int side = p->y() < splitY;
1965         int lastSide = last->y() < splitY;
1966
1967         if (side != lastSide) {
1968             if (qFuzzyCompare(p->y(), splitY)) {
1969                 bin[!side]->append(*p);
1970             } else if (qFuzzyCompare(last->y(), splitY)) {
1971                 bin[side]->append(*last);
1972             } else {
1973                 QPointF delta = *p - *last;
1974                 QPointF intersection(p->x() + delta.x() * (splitY - p->y()) / delta.y(), splitY);
1975
1976                 bin[0]->append(intersection);
1977                 bin[1]->append(intersection);
1978             }
1979         }
1980
1981         bin[side]->append(*p);
1982
1983         last = p;
1984     }
1985
1986     // give up if we couldn't reduce the point count
1987     return upper->size() < pointCount && lower->size() < pointCount;
1988 }
1989
1990 /*!
1991   \internal
1992  */
1993 void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
1994 {
1995     Q_D(QRasterPaintEngine);
1996     QRasterPaintEngineState *s = state();
1997
1998     const int maxPoints = 0xffff;
1999
2000     // max amount of points that raster engine can reliably handle
2001     if (pointCount > maxPoints) {
2002         QVector<QPointF> upper, lower;
2003
2004         if (splitPolygon(points, pointCount, &upper, &lower)) {
2005             fillPolygon(upper.constData(), upper.size(), mode);
2006             fillPolygon(lower.constData(), lower.size(), mode);
2007         } else
2008             qWarning("Polygon too complex for filling.");
2009
2010         return;
2011     }
2012
2013     // Compose polygon fill..,
2014     QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
2015     ensureOutlineMapper();
2016     QT_FT_Outline *outline = d->outlineMapper->convertPath(vp);
2017
2018     // scanconvert.
2019     ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2020                                               &s->brushData);
2021     d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
2022 }
2023
2024 /*!
2025     \reimp
2026 */
2027 void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
2028 {
2029     Q_D(QRasterPaintEngine);
2030     QRasterPaintEngineState *s = state();
2031
2032 #ifdef QT_DEBUG_DRAW
2033     qDebug(" - QRasterPaintEngine::drawPolygon(F), pointCount=%d", pointCount);
2034     for (int i=0; i<pointCount; ++i)
2035         qDebug() << "   - " << points[i];
2036 #endif
2037     Q_ASSERT(pointCount >= 2);
2038
2039     if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
2040         QRectF r(points[0], points[2]);
2041         drawRects(&r, 1);
2042         return;
2043     }
2044
2045     ensurePen();
2046     ensureBrush();
2047     if (mode != PolylineMode) {
2048         // Do the fill...
2049         if (s->brushData.blend) {
2050             d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
2051             fillPolygon(points, pointCount, mode);
2052             d->outlineMapper->setCoordinateRounding(false);
2053         }
2054     }
2055
2056     // Do the outline...
2057     if (s->penData.blend) {
2058         if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
2059             strokePolygonCosmetic(points, pointCount, mode);
2060         else {
2061             QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
2062             QPaintEngineEx::stroke(vp, s->lastPen);
2063         }
2064     }
2065 }
2066
2067 /*!
2068     \reimp
2069 */
2070 void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
2071 {
2072     Q_D(QRasterPaintEngine);
2073     QRasterPaintEngineState *s = state();
2074
2075 #ifdef QT_DEBUG_DRAW
2076     qDebug(" - QRasterPaintEngine::drawPolygon(I), pointCount=%d", pointCount);
2077     for (int i=0; i<pointCount; ++i)
2078         qDebug() << "   - " << points[i];
2079 #endif
2080     Q_ASSERT(pointCount >= 2);
2081     if (mode != PolylineMode && isRect((int *) points, pointCount)) {
2082         QRect r(points[0].x(),
2083                 points[0].y(),
2084                 points[2].x() - points[0].x(),
2085                 points[2].y() - points[0].y());
2086         drawRects(&r, 1);
2087         return;
2088     }
2089
2090     ensureState();
2091     ensurePen();
2092     if (!(s->flags.int_xform && s->flags.fast_pen && (!s->penData.blend || s->pen.brush().isOpaque()))) {
2093         // this calls the float version
2094         QPaintEngineEx::drawPolygon(points, pointCount, mode);
2095         return;
2096     }
2097
2098     // Do the fill
2099     if (mode != PolylineMode) {
2100         ensureBrush();
2101         if (s->brushData.blend) {
2102             // Compose polygon fill..,
2103             ensureOutlineMapper();
2104             d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
2105             d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
2106             d->outlineMapper->moveTo(*points);
2107             const QPoint *p = points;
2108             const QPoint *ep = points + pointCount - 1;
2109             do {
2110                 d->outlineMapper->lineTo(*(++p));
2111             } while (p < ep);
2112             d->outlineMapper->endOutline();
2113
2114             // scanconvert.
2115             ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2116                                                       &s->brushData);
2117             d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
2118             d->outlineMapper->setCoordinateRounding(false);
2119         }
2120     }
2121
2122     // Do the outline...
2123     if (s->penData.blend) {
2124         if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
2125             strokePolygonCosmetic(points, pointCount, mode);
2126         else {
2127             int count = pointCount * 2;
2128             QVarLengthArray<qreal> fpoints(count);
2129 #ifdef Q_WS_MAC
2130             for (int i=0; i<count; i+=2) {
2131                 fpoints[i] = ((int *) points)[i+1];
2132                 fpoints[i+1] = ((int *) points)[i];
2133             }
2134 #else
2135             for (int i=0; i<count; ++i)
2136                 fpoints[i] = ((int *) points)[i];
2137 #endif
2138             QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
2139             QPaintEngineEx::stroke(vp, s->lastPen);
2140         }
2141     }
2142 }
2143
2144 /*!
2145     \internal
2146 */
2147 void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointCount, PolygonDrawMode mode)
2148 {
2149     Q_D(QRasterPaintEngine);
2150     QRasterPaintEngineState *s = state();
2151
2152     Q_ASSERT(s->penData.blend);
2153     Q_ASSERT(s->flags.fast_pen);
2154
2155     bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
2156
2157     // Use fast path for 0 width /  trivial pens.
2158     QIntRect devRect;
2159     devRect.set(d->deviceRect);
2160
2161     LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
2162                                   ? LineDrawIncludeLastPixel
2163                                   : LineDrawNormal);
2164     int dashOffset = int(s->lastPen.dashOffset());
2165
2166     const QPointF offs(aliasedCoordinateDelta, aliasedCoordinateDelta);
2167
2168     // Draw all the line segments.
2169     for (int i=1; i<pointCount; ++i) {
2170
2171         QPointF lp1 = points[i-1] * s->matrix + offs;
2172         QPointF lp2 = points[i] * s->matrix + offs;
2173
2174         const QRectF brect(lp1, lp2);
2175         ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2176         if (qpen_style(s->lastPen) == Qt::SolidLine) {
2177             drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
2178                                 qFloor(lp2.x()), qFloor(lp2.y()),
2179                                 penBlend, &s->penData,
2180                                 i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2181                                 devRect);
2182         } else {
2183             drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
2184                                        qFloor(lp2.x()), qFloor(lp2.y()),
2185                                        &s->lastPen,
2186                                        penBlend, &s->penData,
2187                                        i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2188                                        devRect, &dashOffset);
2189         }
2190     }
2191
2192     // Polygons are implicitly closed.
2193     if (needs_closing) {
2194         QPointF lp1 = points[pointCount-1] * s->matrix + offs;
2195         QPointF lp2 = points[0] * s->matrix + offs;
2196
2197         const QRectF brect(lp1, lp2);
2198         ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2199         if (qpen_style(s->lastPen) == Qt::SolidLine) {
2200             drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
2201                                 qFloor(lp2.x()), qFloor(lp2.y()),
2202                                 penBlend, &s->penData,
2203                                 LineDrawIncludeLastPixel,
2204                                 devRect);
2205         } else {
2206             drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
2207                                        qFloor(lp2.x()), qFloor(lp2.y()),
2208                                        &s->lastPen,
2209                                        penBlend, &s->penData,
2210                                        LineDrawIncludeLastPixel,
2211                                        devRect, &dashOffset);
2212         }
2213     }
2214
2215 }
2216
2217 /*!
2218     \internal
2219 */
2220 void QRasterPaintEngine::strokePolygonCosmetic(const QPoint *points, int pointCount, PolygonDrawMode mode)
2221 {
2222     Q_D(QRasterPaintEngine);
2223     QRasterPaintEngineState *s = state();
2224
2225     // We assert here because this function is called from drawRects
2226     // and drawPolygon and they already do ensurePen(), so we skip that
2227     // here to avoid duplicate checks..
2228     Q_ASSERT(s->penData.blend);
2229
2230     bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
2231
2232     QIntRect devRect;
2233     devRect.set(d->deviceRect);
2234
2235     LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
2236                                   ? LineDrawIncludeLastPixel
2237                                   : LineDrawNormal);
2238
2239     int m11 = int(s->matrix.m11());
2240     int m22 = int(s->matrix.m22());
2241     int dx = int(s->matrix.dx());
2242     int dy = int(s->matrix.dy());
2243     int m13 = int(s->matrix.m13());
2244     int m23 = int(s->matrix.m23());
2245     bool affine = !m13 && !m23;
2246
2247     int dashOffset = int(s->lastPen.dashOffset());
2248
2249     if (affine) {
2250         // Draw all the line segments.
2251         for (int i=1; i<pointCount; ++i) {
2252             const QPoint lp1 = points[i-1] * s->matrix;
2253             const QPoint lp2 = points[i] * s->matrix;
2254             const QRect brect(lp1, lp2);
2255             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2256
2257             if (qpen_style(s->lastPen) == Qt::SolidLine)
2258                 drawLine_midpoint_i(lp1.x(), lp1.y(),
2259                                     lp2.x(), lp2.y(),
2260                                     penBlend, &s->penData,
2261                                     i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2262                                     devRect);
2263             else
2264                 drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
2265                                            lp2.x(), lp2.y(),
2266                                            &s->lastPen,
2267                                            penBlend, &s->penData,
2268                                            i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2269                                            devRect, &dashOffset);
2270
2271         }
2272
2273         // Polygons are implicitly closed.
2274         if (needs_closing) {
2275             const QPoint lp1 = points[pointCount - 1] * s->matrix;
2276             const QPoint lp2 = points[0] * s->matrix;
2277             const QRect brect(lp1, lp2);
2278             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2279
2280             if (qpen_style(s->lastPen) == Qt::SolidLine)
2281                 drawLine_midpoint_i(lp1.x(), lp1.y(),
2282                                     lp2.x(), lp2.y(),
2283                                     penBlend, &s->penData, LineDrawIncludeLastPixel,
2284                                     devRect);
2285             else
2286                 drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
2287                                            lp2.x(), lp2.y(),
2288                                            &s->lastPen,
2289                                            penBlend, &s->penData, LineDrawIncludeLastPixel,
2290                                            devRect, &dashOffset);
2291         }
2292     } else {
2293         // Draw all the line segments.
2294         for (int i=1; i<pointCount; ++i) {
2295             int x1 = points[i-1].x() * m11 + dx;
2296             int y1 = points[i-1].y() * m22 + dy;
2297             qreal w = m13*points[i-1].x() + m23*points[i-1].y() + 1.;
2298             w = 1/w;
2299             x1 = int(x1*w);
2300             y1 = int(y1*w);
2301             int x2 = points[i].x() * m11 + dx;
2302             int y2 = points[i].y() * m22 + dy;
2303             w = m13*points[i].x() + m23*points[i].y() + 1.;
2304             w = 1/w;
2305             x2 = int(x2*w);
2306             y2 = int(y2*w);
2307
2308             const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
2309             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2310             if (qpen_style(s->lastPen) == Qt::SolidLine)
2311                 drawLine_midpoint_i(x1, y1, x2, y2,
2312                                     penBlend, &s->penData,
2313                                     i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2314                                     devRect);
2315             else
2316                 drawLine_midpoint_dashed_i(x1, y1, x2, y2,
2317                                            &s->lastPen,
2318                                            penBlend, &s->penData,
2319                                            i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
2320                                            devRect, &dashOffset);
2321
2322         }
2323
2324         int x1 = points[pointCount-1].x() * m11 + dx;
2325         int y1 = points[pointCount-1].y() * m22 + dy;
2326         qreal w = m13*points[pointCount-1].x() + m23*points[pointCount-1].y() + 1.;
2327         w = 1/w;
2328         x1 = int(x1*w);
2329         y1 = int(y1*w);
2330         int x2 = points[0].x() * m11 + dx;
2331         int y2 = points[0].y() * m22 + dy;
2332         w = m13*points[0].x() + m23*points[0].y() + 1.;
2333         w = 1/w;
2334         x2 = int(x2 * w);
2335         y2 = int(y2 * w);
2336         // Polygons are implicitly closed.
2337
2338         if (needs_closing) {
2339             const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
2340             ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
2341             if (qpen_style(s->lastPen) == Qt::SolidLine)
2342                 drawLine_midpoint_i(x1, y1, x2, y2,
2343                                     penBlend, &s->penData, LineDrawIncludeLastPixel,
2344                                     devRect);
2345             else
2346                 drawLine_midpoint_dashed_i(x1, y1, x2, y2,
2347                                            &s->lastPen,
2348                                            penBlend, &s->penData, LineDrawIncludeLastPixel,
2349                                            devRect, &dashOffset);
2350         }
2351     }
2352 }
2353
2354 /*!
2355     \internal
2356 */
2357 void QRasterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pixmap)
2358 {
2359 #ifdef QT_DEBUG_DRAW
2360     qDebug() << " - QRasterPaintEngine::drawPixmap(), pos=" << pos << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2361 #endif
2362
2363     QPixmapData *pd = pixmap.pixmapData();
2364     if (pd->classId() == QPixmapData::RasterClass) {
2365         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2366         if (image.depth() == 1) {
2367             Q_D(QRasterPaintEngine);
2368             QRasterPaintEngineState *s = state();
2369             if (s->matrix.type() <= QTransform::TxTranslate) {
2370                 ensurePen();
2371                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2372             } else {
2373                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2374             }
2375         } else {
2376             QRasterPaintEngine::drawImage(pos, image);
2377         }
2378     } else {
2379         const QImage image = pixmap.toImage();
2380         if (pixmap.depth() == 1) {
2381             Q_D(QRasterPaintEngine);
2382             QRasterPaintEngineState *s = state();
2383             if (s->matrix.type() <= QTransform::TxTranslate) {
2384                 ensurePen();
2385                 drawBitmap(pos + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2386             } else {
2387                 drawImage(pos, d->rasterBuffer->colorizeBitmap(image, s->pen.color()));
2388             }
2389         } else {
2390             QRasterPaintEngine::drawImage(pos, image);
2391         }
2392     }
2393 }
2394
2395 /*!
2396     \reimp
2397 */
2398 void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
2399 {
2400 #ifdef QT_DEBUG_DRAW
2401     qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
2402 #endif
2403
2404     QPixmapData* pd = pixmap.pixmapData();
2405     if (pd->classId() == QPixmapData::RasterClass) {
2406         const QImage &image = static_cast<QRasterPixmapData *>(pd)->image;
2407         if (image.depth() == 1) {
2408             Q_D(QRasterPaintEngine);
2409             QRasterPaintEngineState *s = state();
2410             if (s->matrix.type() <= QTransform::TxTranslate
2411                 && r.size() == sr.size()
2412                 && r.size() == pixmap.size()) {
2413                 ensurePen();
2414                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2415                 return;
2416             } else {
2417                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), sr);
2418             }
2419         } else {
2420             drawImage(r, image, sr);
2421         }
2422     } else {
2423         QRect clippedSource = sr.toAlignedRect().intersected(pixmap.rect());
2424         const QImage image = pd->toImage(clippedSource);
2425         QRectF translatedSource = sr.translated(-clippedSource.topLeft());
2426         if (image.depth() == 1) {
2427             Q_D(QRasterPaintEngine);
2428             QRasterPaintEngineState *s = state();
2429             if (s->matrix.type() <= QTransform::TxTranslate
2430                 && r.size() == sr.size()
2431                 && r.size() == pixmap.size()) {
2432                 ensurePen();
2433                 drawBitmap(r.topLeft() + QPointF(s->matrix.dx(), s->matrix.dy()), image, &s->penData);
2434                 return;
2435             } else {
2436                 drawImage(r, d->rasterBuffer->colorizeBitmap(image, s->pen.color()), translatedSource);
2437             }
2438         } else {
2439             drawImage(r, image, translatedSource);
2440         }
2441     }
2442 }
2443
2444 // assumes that rect has positive width and height
2445 static inline const QRect toRect_normalized(const QRectF &rect)
2446 {
2447     const int x = qRound(rect.x());
2448     const int y = qRound(rect.y());
2449     const int w = int(rect.width() + qreal(0.5));
2450     const int h = int(rect.height() + qreal(0.5));
2451
2452     return QRect(x, y, w, h);
2453 }
2454
2455 static inline int fast_ceil_positive(const qreal &v)
2456 {
2457     const int iv = int(v);
2458     if (v - iv == 0)
2459         return iv;
2460     else
2461         return iv + 1;
2462 }
2463
2464 static inline const QRect toAlignedRect_positive(const QRectF &rect)
2465 {
2466     const int xmin = int(rect.x());
2467     const int xmax = int(fast_ceil_positive(rect.right()));
2468     const int ymin = int(rect.y());
2469     const int ymax = int(fast_ceil_positive(rect.bottom()));
2470     return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
2471 }
2472
2473 /*!
2474     \internal
2475 */
2476 void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
2477 {
2478 #ifdef QT_DEBUG_DRAW
2479     qDebug() << " - QRasterPaintEngine::drawImage(), p=" <<  p << " image=" << img.size() << "depth=" << img.depth();
2480 #endif
2481
2482     Q_D(QRasterPaintEngine);
2483     QRasterPaintEngineState *s = state();
2484
2485     if (s->matrix.type() > QTransform::TxTranslate) {
2486         drawImage(QRectF(p.x(), p.y(), img.width(), img.height()),
2487                   img,
2488                   QRectF(0, 0, img.width(), img.height()));
2489     } else {
2490
2491         const QClipData *clip = d->clip();
2492         QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2493
2494         if (s->flags.fast_images) {
2495             SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2496             if (func) {
2497                 if (!clip) {
2498                     d->drawImage(pt, img, func, d->deviceRect, s->intOpacity);
2499                     return;
2500                 } else if (clip->hasRectClip) {
2501                     d->drawImage(pt, img, func, clip->clipRect, s->intOpacity);
2502                     return;
2503                 }
2504             }
2505         }
2506
2507
2508
2509         d->image_filler.clip = clip;
2510         d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2511         if (!d->image_filler.blend)
2512             return;
2513         d->image_filler.dx = -pt.x();
2514         d->image_filler.dy = -pt.y();
2515         QRect rr = img.rect().translated(qRound(pt.x()), qRound(pt.y()));
2516
2517         fillRect_normalized(rr, &d->image_filler, d);
2518     }
2519
2520 }
2521
2522 QRectF qt_mapRect_non_normalizing(const QRectF &r, const QTransform &t)
2523 {
2524     return QRectF(r.topLeft() * t, r.bottomRight() * t);
2525 }
2526
2527 namespace {
2528     enum RotationType {
2529         Rotation90,
2530         Rotation180,
2531         Rotation270,
2532         NoRotation
2533     };
2534
2535     inline RotationType qRotationType(const QTransform &transform)
2536     {
2537         QTransform::TransformationType type = transform.type();
2538
2539         if (type > QTransform::TxRotate)
2540             return NoRotation;
2541
2542         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(-1))
2543             && qFuzzyCompare(transform.m21(), qreal(1)) && qFuzzyIsNull(transform.m22()))
2544             return Rotation90;
2545
2546         if (type == QTransform::TxScale && qFuzzyCompare(transform.m11(), qreal(-1)) && qFuzzyIsNull(transform.m12())
2547             && qFuzzyIsNull(transform.m21()) && qFuzzyCompare(transform.m22(), qreal(-1)))
2548             return Rotation180;
2549
2550         if (type == QTransform::TxRotate && qFuzzyIsNull(transform.m11()) && qFuzzyCompare(transform.m12(), qreal(1))
2551             && qFuzzyCompare(transform.m21(), qreal(-1)) && qFuzzyIsNull(transform.m22()))
2552             return Rotation270;
2553
2554         return NoRotation;
2555     }
2556
2557     inline bool isPixelAligned(const QRectF &rect) {
2558         return QRectF(rect.toRect()) == rect;
2559     }
2560 }
2561
2562 /*!
2563     \reimp
2564 */
2565 void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
2566                                    Qt::ImageConversionFlags)
2567 {
2568 #ifdef QT_DEBUG_DRAW
2569     qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2570 #endif
2571
2572     if (r.isEmpty())
2573         return;
2574
2575     Q_D(QRasterPaintEngine);
2576     QRasterPaintEngineState *s = state();
2577     int sr_l = qFloor(sr.left());
2578     int sr_r = qCeil(sr.right()) - 1;
2579     int sr_t = qFloor(sr.top());
2580     int sr_b = qCeil(sr.bottom()) - 1;
2581
2582     if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2583         // as fillRect will apply the aliased coordinate delta we need to
2584         // subtract it here as we don't use it for image drawing
2585         QTransform old = s->matrix;
2586         s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2587
2588         // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2589         QRgb color = img.pixel(sr_l, sr_t);
2590         switch (img.format()) {
2591         case QImage::Format_ARGB32_Premultiplied:
2592         case QImage::Format_ARGB8565_Premultiplied:
2593         case QImage::Format_ARGB6666_Premultiplied:
2594         case QImage::Format_ARGB8555_Premultiplied:
2595         case QImage::Format_ARGB4444_Premultiplied:
2596             // Combine premultiplied color with the opacity set on the painter.
2597             d->solid_color_filler.solid.color =
2598                 ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2599                 | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2600             break;
2601         default:
2602             d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2603             break;
2604         }
2605
2606         if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2607             && s->composition_mode == QPainter::CompositionMode_SourceOver) {
2608             return;