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