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