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