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